EightyOne capabilities
Every operation EightyOne exposes to code and agents. Each is one capability: the REST API (/api/v1, OpenAPI at /api/v1/openapi.json) and the MCP server (/mcp) are generated from these definitions, so they cannot disagree.
MCP: read capabilities only for now. A capability is either a listed tool or reached through
capabilities_search/capabilities_call; an agent sees only what its credential may run.Auth:
Authorization: Bearer <API key>(orX-API-Key). The key's company is the company; a key acts as its owner, narrowed to the key's permissions.Errors: RFC 9457
application/problem+jsonwith a stablecode.Writes: send
Idempotency-Key: <unique>to make a retry safe (24 h). Where marked,Prefer: dry-runruns the write, rolls it back and returns the planned changes.
Account
me.get: Who am I
The caller: the user this credential acts as, the company it is bound to, how it is calling (REST or MCP; human, agent or service account) and the permissions it actually has here (the union of the user's roles' groups ∩ the credential's permissions). Call it first to know what you can do.
REST: GET /api/v1/me · Permission: any member of the company · Effect: read · MCP: tool me_get
Output
| Field | Type | Required | Description |
|---|---|---|---|
user |
object | yes | |
company |
object | yes | |
actorType |
human | agent | service |
yes | |
channel |
string | yes | |
permissions |
string[] | yes |
Guides
guide.get: Read a guide
EightyOne concepts and how to read the data: the glossary, downtime, maintenance, production, inventory, quality, commissioning, what deserves attention, and this company's own guidance (topic "company"). Without a topic, lists the topics. Read the glossary before working on an unfamiliar area.
REST: GET /api/v1/guides · Permission: any member of the company · Effect: read · MCP: tool guide_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
topic |
glossary | downtime | maintenance | production | inventory | quality | commissioning | signals | company |
"company": what this company's administrators tell agents, including notes on specific machines |
Output
| Field | Type | Required | Description |
|---|---|---|---|
topic |
string | null | yes | |
title |
string | yes | |
body |
string | yes | Markdown |
topics |
object[] | yes |
guidance.list: List company guidance for agents
What the company's administrators tell every AI agent: company-wide guidance and notes on specific machines, work centers, products and task types, with any thresholds they set.
REST: GET /api/v1/guidance · Permission: any member of the company · Effect: read · MCP: via capabilities_call
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
subject |
company | ssu | work_center | product | task_type |
yes | |
ref |
string | null | yes | The SSU / product / task type external id, or the work center name |
name |
string | null | yes | What it's about, by name |
body |
string | yes | |
thresholds |
object | yes | |
version |
integer | yes | |
reviewedAt |
string (date-time) | null | yes | |
updatedAt |
string (date-time) | yes |
guidance.set: Set company guidance for agents
Write the guidance agents get for the company, or for one machine, work center, product or task type. Replaces that subject's text; the previous version is kept in the audit log. Every agent connected to the company follows it.
REST: PUT /api/v1/guidance · Permission: ai_guidance:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
subject |
company | ssu | work_center | product | task_type |
yes | |
ref |
string | Which one (not for company): SSU external id, work center name, product external id or SKU, task type external id | |
body |
string | yes | Plain text or Markdown. Company: up to 4000 characters; one subject: 1000 |
thresholds |
object | ||
reviewed |
boolean | true | false |
Mark it as reviewed now (agents see how fresh it is) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
subject |
company | ssu | work_center | product | task_type |
yes | |
ref |
string | null | yes | The SSU / product / task type external id, or the work center name |
name |
string | null | yes | What it's about, by name |
body |
string | yes | |
thresholds |
object | yes | |
version |
integer | yes | |
reviewedAt |
string (date-time) | null | yes | |
updatedAt |
string (date-time) | yes |
guidance.delete: Remove company guidance for agents
Remove the guidance for the company or one subject. The audit log keeps what it said.
REST: DELETE /api/v1/guidance · Permission: ai_guidance:manage · Effect: destructive · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
subject |
company | ssu | work_center | product | task_type |
yes | |
ref |
string |
Tasks
tasks.list: List tasks
Tasks, newest first. Everything in EightyOne is a task (work-order operations, maintenance, inspections, NCRs, approvals…). Open tasks only unless a status is given or includeCompleted=true. Without the 'See all tasks' permission you see only tasks assigned to you, plus your teams' tasks with 'See tasks for my team'.
REST: GET /api/v1/tasks · Permission: any member of the company · Effect: read · MCP: tool tasks_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip | |
status |
open | preparation | ready | dispatched | submitted | incomplete | done | declined |
||
typeId |
string | Task type external id | |
ssuId |
string | SSU external id | |
includeCompleted |
boolean | true | false |
Include done and declined tasks |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
tasks.get: Get a task
One task by its id.
REST: GET /api/v1/tasks/:id · Permission: any member of the company · Effect: read · MCP: tool tasks_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
tasks.create: Create a task
Create a task of a task type, exactly as the dashboard does: the type's defaults apply (SLA due date, default assignee, transit, created-as-ready), and the task.created webhook fires. Needs 'Create tasks' unless the type is user-generated.
REST: POST /api/v1/tasks · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool tasks_create
Input
| Field | Type | Required | Description |
|---|---|---|---|
typeId |
string | yes | Task type external id |
title |
string | yes | |
details |
string | ||
status |
open | preparation | ready | dispatched | submitted | incomplete | done |
||
startDate |
string (date-time) | string (date) | ||
endDate |
string (date-time) | string (date) | ||
dueDate |
string (date-time) | string (date) | Defaults to the type's SLA for the priority | |
priorityId |
integer | ||
ssuId |
string | SSU external id | |
externalSystemId |
string | ||
fromStorageUnitId |
integer | ||
toStorageUnitId |
integer | ||
fromVendorId |
integer | ||
toVendorId |
integer | ||
assigneeIds |
integer[] | Personnel ids | |
incompleteReason |
string | Required when status is 'incomplete' | |
after |
object | Link the new task to an existing one: dependency (it waits for that task) or follow |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
tasks.update: Update a task
Change a task, with the dashboard's rules: status changes need 'Change task status from mobile' (assignees may still complete their own work), reassigning needs 'Reassign tasks', blocked tasks can't progress, producing tasks complete with goodQuantity / scrapQuantity (counts during the run: tasks_record_counts), maintenance types may need failure codes (problemCodeId, causeCodeId, remedyCodeId) to complete, 'incomplete' needs a reason and can create a follow-up (createFollowUp), 'declined' needs a reason. Tasks sent to a partner only accept details, dueDate and priorityId.
REST: PATCH /api/v1/tasks/:id · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool tasks_update
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
title |
string | ||
details |
string | ||
status |
open | preparation | ready | dispatched | submitted | incomplete | done | declined |
||
startDate |
string (date-time) | string (date) | null | ||
endDate |
string (date-time) | string (date) | null | ||
dueDate |
string (date-time) | string (date) | null | ||
priorityId |
integer | ||
ssuId |
string | null | SSU external id, or null to clear | |
externalSystemId |
string | ||
assigneeIds |
integer[] | Personnel ids: replaces the assignees | |
incompleteReason |
string | ||
declinedReason |
string | ||
createFollowUp |
boolean | With status 'incomplete': create a follow-up task for the rest | |
goodQuantity |
number | ||
scrapQuantity |
number | ||
scrapReasonCodeId |
integer | ||
problemCodeId |
integer | Failure coding (reason_codes_list kind failure_problem); types that require it can't complete without all three | |
causeCodeId |
integer | Failure coding: kind failure_cause | |
remedyCodeId |
integer | Failure coding: kind failure_remedy |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
_meta |
object | yes |
tasks.record_counts: Record production counts
Add good and scrap quantities to a running work-order operation or producing task, as operators do from the app. Counts add up and feed OEE; the output posts to stock once, when the task completes. To count at completion instead, pass goodQuantity / scrapQuantity to tasks.update with the status.
REST: POST /api/v1/tasks/:id/counts · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool tasks_record_counts
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
goodQuantity |
number | ||
scrapQuantity |
number | ||
scrapReasonCodeId |
integer | A scrap reason (reason_codes_list, kind scrap) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
goodQuantity |
number | yes | |
scrapQuantity |
number | yes | |
scrapReasonCodeId |
integer | null | yes |
tasks.connect: Connect two tasks
Link two tasks. 'dependency': the second waits for the first. It can't progress until the first is done, and goes back to open if it was already ready or dispatched (it becomes ready if the first is already done). 'follow': only records that the second follows the first. Connections are removed in the dashboard.
REST: POST /api/v1/tasks/:from/connections · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool tasks_connect
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | yes | The first task's external id |
to |
string | yes | The external id of the task that waits for or follows it |
type |
dependency | follow |
yes | |
description |
string |
Output
| Field | Type | Required | Description |
|---|---|---|---|
from |
string | yes | |
to |
string | yes | |
type |
string | yes | |
description |
string | null | yes | |
toStatus |
string | yes | The second task's status after connecting |
tasks.delete: Delete a task
Delete a task, as the dashboard does: a task you sent to a partner withdraws the handoff; a task a partner sent you can't be deleted (decline it instead).
REST: DELETE /api/v1/tasks/:id · Permission: tasks:delete · Effect: destructive · Idempotency-Key: accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
tasks.get_form: A task's form
The fields a task's form records, in order: type, whether it's required, the choices of a select, the limits of a measurement, whether a condition hides it, and the current answer. Answer them with tasks_submit_form.
REST: GET /api/v1/tasks/:id/form · Permission: any member of the company · Effect: read · MCP: tool tasks_get_form
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
fields |
object[] | yes |
tasks.submit_form: Fill in a task's form
Answer a task's form fields by title (tasks_get_form lists them), and optionally complete the task (status done or submitted) or mark it incomplete, as the app does. Completing needs every required field; measurements outside their limits open an NCR; machine-status fields set the machine's status. Counts and failure codes go with the completion, as in tasks_update. Preview it first.
REST: POST /api/v1/tasks/:id/form · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool tasks_submit_form
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
answers |
object[] | yes | Answers by field title; fields left out keep their answer |
status |
done | submitted | incomplete |
Complete it (done, or submitted for review) or mark it incomplete; leave out to only save the answers | |
incompleteReason |
string | ||
createFollowUp |
boolean | ||
goodQuantity |
number | ||
scrapQuantity |
number | ||
scrapReasonCodeId |
integer | ||
problemCodeId |
integer | ||
causeCodeId |
integer | ||
remedyCodeId |
integer |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
failedChecks |
string[] | yes | |
ncrId |
string | null | yes |
Task types
task_types.list: List task types
The company's task types: the templates every task is created from (work orders' operations, maintenance, NCRs, inspections, approvals…), alphabetically. Use a type's id as typeId when creating a task.
REST: GET /api/v1/task-types · Permission: any member of the company · Effect: read · MCP: tool task_types_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task type external id |
typeName |
string | yes | |
color |
string | null | yes | |
isQuote |
boolean | yes | |
isUserGenerated |
boolean | yes | Field users may create tasks of this type themselves |
isDataRequest |
boolean | yes | Tasks of this type ask a partner company for traceability data |
isRemote |
boolean | yes | |
isInventory |
boolean | yes | |
defaultUseTransit |
boolean | yes | Inventory tasks stage stock through the transit bin by default |
isBulk |
boolean | yes | |
workCenterId |
integer | null | yes | |
team |
object | null | yes | The team whose members see and take this type's tasks. Changing it moves every task of the type |
parentProductId |
integer | null | yes | The product a production operation of this type makes |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
task_types.get: Get a task type
One task type by its id.
REST: GET /api/v1/task-types/:id · Permission: any member of the company · Effect: read · MCP: tool task_types_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task type external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task type external id |
typeName |
string | yes | |
color |
string | null | yes | |
isQuote |
boolean | yes | |
isUserGenerated |
boolean | yes | Field users may create tasks of this type themselves |
isDataRequest |
boolean | yes | Tasks of this type ask a partner company for traceability data |
isRemote |
boolean | yes | |
isInventory |
boolean | yes | |
defaultUseTransit |
boolean | yes | Inventory tasks stage stock through the transit bin by default |
isBulk |
boolean | yes | |
workCenterId |
integer | null | yes | |
team |
object | null | yes | The team whose members see and take this type's tasks. Changing it moves every task of the type |
parentProductId |
integer | null | yes | The product a production operation of this type makes |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
Teams
teams.list: List teams
The company's teams, alphabetically, with their members' personnel ids. A task belongs to its task type's team: team members with 'See tasks for my team' see those tasks and can take them in the field.
REST: GET /api/v1/teams · Permission: any member of the company · Effect: read · MCP: via capabilities_call
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Team id |
name |
string | yes | |
color |
string | yes | |
memberIds |
integer[] | yes | Personnel ids of the members |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
teams.create: Create a team
Create a team, optionally with its members. Point task types at it to give it work.
REST: POST /api/v1/teams · Permission: settings:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | |
color |
string | Hex color, e.g. #026485 | |
memberIds |
integer[] | Personnel ids: replaces the members |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Team id |
name |
string | yes | |
color |
string | yes | |
memberIds |
integer[] | yes | Personnel ids of the members |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
teams.update: Update a team
Rename or recolor a team, or replace its members (memberIds). Only the fields sent change. Members see the team's tasks at once.
REST: PATCH /api/v1/teams/:id · Permission: settings:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | ||
color |
string | Hex color, e.g. #026485 | |
memberIds |
integer[] | Personnel ids: replaces the members |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Team id |
name |
string | yes | |
color |
string | yes | |
memberIds |
integer[] | yes | Personnel ids of the members |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
teams.delete: Delete a team
Delete a team and its memberships. Refused while a task type still belongs to it: move those types to another team (or none) first.
REST: DELETE /api/v1/teams/:id · Permission: settings:manage · Effect: destructive · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Clients
clients.list: List clients
The company's clients (the customers whose sites and SSUs work happens at), newest first. Filter by name or active flag.
REST: GET /api/v1/clients · Permission: any member of the company · Effect: read · MCP: tool clients_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip | |
search |
string | Case-insensitive name contains | |
isActive |
boolean | true | false |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | null | yes | Your id for the client (its external system id). null for clients created in EightyOne without one: they are listed, but can't be fetched or changed by id over the API |
name |
string | yes | |
isActive |
boolean | yes | |
contactPersonName |
string | null | yes | |
contactPersonEmail |
string | null | yes | |
contactPersonPhone |
string | null | yes | |
freeText |
string | null | yes | |
color |
string | null | yes | |
isDefault |
boolean | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
clients.get: Get a client
One client by your id for it.
REST: GET /api/v1/clients/:id · Permission: any member of the company · Effect: read · MCP: tool clients_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | null | yes | Your id for the client (its external system id). null for clients created in EightyOne without one: they are listed, but can't be fetched or changed by id over the API |
name |
string | yes | |
isActive |
boolean | yes | |
contactPersonName |
string | null | yes | |
contactPersonEmail |
string | null | yes | |
contactPersonPhone |
string | null | yes | |
freeText |
string | null | yes | |
color |
string | null | yes | |
isDefault |
boolean | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
clients.create: Create a client
Create a client with your own id for it (used to address it afterwards). Fires the client.created webhook.
REST: POST /api/v1/clients · Permission: clients:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Your id for the client; must be unique in the company |
name |
string | yes | |
contactPersonName |
string | null | ||
contactPersonEmail |
string (email) | null | ||
contactPersonPhone |
string | null | ||
freeText |
string | null | ||
color |
string | ||
isDefault |
boolean | Make this the company's default client (unsets the previous default) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | null | yes | Your id for the client (its external system id). null for clients created in EightyOne without one: they are listed, but can't be fetched or changed by id over the API |
name |
string | yes | |
isActive |
boolean | yes | |
contactPersonName |
string | null | yes | |
contactPersonEmail |
string | null | yes | |
contactPersonPhone |
string | null | yes | |
freeText |
string | null | yes | |
color |
string | null | yes | |
isDefault |
boolean | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
clients.update: Update a client
Change any of a client's fields; only the fields sent change.
REST: PATCH /api/v1/clients/:id · Permission: clients:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | ||
isActive |
boolean | ||
contactPersonName |
string | null | ||
contactPersonEmail |
string (email) | null | ||
contactPersonPhone |
string | null | ||
freeText |
string | null | ||
color |
string | ||
isDefault |
boolean | Make this the company's default client (unsets the previous default) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | null | yes | Your id for the client (its external system id). null for clients created in EightyOne without one: they are listed, but can't be fetched or changed by id over the API |
name |
string | yes | |
isActive |
boolean | yes | |
contactPersonName |
string | null | yes | |
contactPersonEmail |
string | null | yes | |
contactPersonPhone |
string | null | yes | |
freeText |
string | null | yes | |
color |
string | null | yes | |
isDefault |
boolean | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
clients.delete: Delete a client
Delete (archive) a client. Its history is kept.
REST: DELETE /api/v1/clients/:id · Permission: clients:manage · Effect: destructive · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
SSUs
ssus.list: List SSUs
The company's SSUs (sub-site units: machines, assets, locations within a site), newest first.
REST: GET /api/v1/ssus · Permission: any member of the company · Effect: read · MCP: tool ssus_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | SSU external id (also its QR identity) |
name |
string | yes | |
imageUrl |
string | null | yes | |
isActive |
boolean | yes | |
isDefault |
boolean | yes | |
location |
any | null | yes | GeoJSON point (PostGIS geometry), or null |
make |
string | null | yes | Machine make, from the global machine catalog (factories) |
model |
string | null | yes | Machine model, from the global machine catalog |
sku |
string | null | yes | Model-level SKU / part number (not a serial number) |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
ssus.get: Get an SSU
One SSU by its external id, with the company's guidance note on it for agents (if any): read it before drawing conclusions about this machine.
REST: GET /api/v1/ssus/:id · Permission: any member of the company · Effect: read · MCP: tool ssus_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | SSU external id (also its QR identity) |
name |
string | yes | |
imageUrl |
string | null | yes | |
isActive |
boolean | yes | |
isDefault |
boolean | yes | |
location |
any | null | yes | GeoJSON point (PostGIS geometry), or null |
make |
string | null | yes | Machine make, from the global machine catalog (factories) |
model |
string | null | yes | Machine model, from the global machine catalog |
sku |
string | null | yes | Model-level SKU / part number (not a serial number) |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
guidance |
object | null | yes | What the company's administrators tell agents about this SSU |
ssus.update: Update an SSU
Change an SSU's name, image, active flag, default flag or location. Making it the default unsets the default on the other SSUs of its sites.
REST: PUT /api/v1/ssus/:id · Permission: clients:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | ||
imageUrl |
string | ||
isActive |
boolean | ||
isDefault |
boolean | ||
location |
object |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | SSU external id (also its QR identity) |
name |
string | yes | |
imageUrl |
string | null | yes | |
isActive |
boolean | yes | |
isDefault |
boolean | yes | |
location |
any | null | yes | GeoJSON point (PostGIS geometry), or null |
make |
string | null | yes | Machine make, from the global machine catalog (factories) |
model |
string | null | yes | Machine model, from the global machine catalog |
sku |
string | null | yes | Model-level SKU / part number (not a serial number) |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
Inventory
line_items.find_ssu_by_barcode: Find the SSU holding a scanned unit
Resolve a scanned line-item barcode to the SSU (machine / location) whose storage unit holds it. 404 when the unit, its storage unit or that storage unit's SSU is unknown.
REST: GET /api/v1/line-items/ssu · Permission: any member of the company · Effect: read · MCP: tool line_items_find_ssu_by_barcode
Input
| Field | Type | Required | Description |
|---|---|---|---|
barcode |
string | yes | Line item barcode (code) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
imageUrl |
string | null | yes | |
isActive |
boolean | yes | |
location |
any | null | yes | GeoJSON point (PostGIS geometry), or null |
stock_transactions.list: Export stock movements
The stock movement ledger (consumption, receipts, transfers, shipments), newest first, for pull-based ERP sync. Quantities only.
REST: GET /api/v1/stock-transactions · Permission: inventory:view · Effect: read · MCP: tool stock_transactions_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | Movements at or after this time | |
to |
string (date-time) | Movements before this time | |
limit |
integer |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
time |
string (date-time) | yes | |
quantity |
number | yes | |
bin |
string | null | yes | goods, bads, installed, transit, quarantine |
itemId |
integer | null | yes | Line item (unit) id |
fromStorageUnitId |
integer | null | yes | |
toStorageUnitId |
integer | null | yes | |
fromVendorId |
integer | null | yes | |
toVendorId |
integer | null | yes | |
toClientId |
integer | null | yes | |
toCustomerId |
integer | null | yes | |
taskId |
integer | null | yes | |
lotId |
integer | null | yes | |
serialId |
integer | null | yes | |
reasonCodeId |
integer | null | yes | |
stockTransactionGroupId |
integer | null | yes |
inventory.stock_levels: Stock on hand
Goods on hand per product and storage site (up to 2000 rows), by the same rule reordering uses: good stock only (not the bads bin), not counting stock held by a partner. Filter by product id, SKU or storage site.
REST: GET /api/v1/inventory/stock-levels · Permission: inventory:view · Effect: read · MCP: tool inventory_stock_levels
Input
| Field | Type | Required | Description |
|---|---|---|---|
productId |
string | Product external id | |
sku |
string | Product SKU (case-insensitive) | |
storageSiteId |
string | Storage site external id |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
productId |
string | yes | |
sku |
string | null | yes | |
name |
string | yes | |
uom |
string | null | yes | |
itemClass |
string | yes | raw, wip, finished, operations or spare_part |
storageSiteId |
string | null | yes | |
storageSiteName |
string | null | yes | |
onHand |
number | yes |
inventory.reorder_suggestions: Reorder suggestions
Products below their minimum or at their dynamic reorder point (lead time × measured consumption), with the suggested quantity and vendor. Quantities and days only.
REST: GET /api/v1/inventory/reorder-suggestions · Permission: products:view · Effect: read · MCP: tool inventory_reorder_suggestions
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
productName |
string | yes | |
sku |
string | null | yes | |
onHand |
number | yes | |
minQty |
number | yes | |
suggestedQty |
number | yes | |
suggestedVendorName |
string | null | yes | |
vendorLeadTime |
number | null | yes | Days |
dailyConsumption |
number | null | yes | |
reorderPoint |
number | null | yes | |
triggerReason |
below_min | below_reorder_point |
yes |
storage_units.list: List storage units
Where stock sits: each storage unit (shelf, rack, bay, dock…) with its storage site and whose it is: warehouse or site (the company's own), client, personnel (a technician's van), customer_consigned, partner.
REST: GET /api/v1/storage-units · Permission: inventory:view · Effect: read · MCP: tool storage_units_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
storageSiteId |
string | Storage site external id |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Storage unit external id |
name |
string | yes | |
site |
object | null | yes |
storage_units.get: What's in a storage unit
A storage unit and everything in it: per product, bin (goods / bads / quarantine), lot and serial.
REST: GET /api/v1/storage-units/:id · Permission: inventory:view · Effect: read · MCP: tool storage_units_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Storage unit external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Storage unit external id |
name |
string | yes | |
site |
object | null | yes | |
contents |
object[] | yes |
stock.transfer: Move stock
Move stock between storage units, or between bins in one unit, as the dashboard's transfers do: name the product by SKU, and the lot or serial when it's tracked. It can't move more than is there. Needs 'Manage inventory'.
REST: POST /api/v1/stock/transfers · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool stock_transfer
Input
| Field | Type | Required | Description |
|---|---|---|---|
sku |
string | yes | |
quantity |
number | yes | |
from |
string | yes | Storage unit external id it leaves |
to |
string | yes | Storage unit external id it goes to |
bin |
goods | bads | quarantine |
The bin it's taken from | |
toBin |
goods | bads | quarantine |
The bin it lands in (default: the same) | |
lotCode |
string | Which lot, for lot-tracked products | |
serialCode |
string | Which unit, for serialized products |
Output
| Field | Type | Required | Description |
|---|---|---|---|
sku |
string | yes | |
quantity |
number | yes | |
from |
object | yes | |
to |
object | yes | |
bin |
string | yes | |
toBin |
string | yes | |
lotCode |
string | null | yes |
purchase_orders.list: List purchase orders
Purchase orders (purchase requests): vendor, status, and each line's product, quantity ordered and received. Quantities only: EightyOne holds no prices.
REST: GET /api/v1/purchase-orders · Permission: any member of the company · Effect: read · MCP: tool purchase_orders_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
status |
string | e.g. open, partially_received, received |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
name |
string | null | yes | |
status |
string | yes | |
vendor |
string | null | yes | |
externalSystemId |
string | null | yes | |
lines |
object[] | yes |
purchase_orders.receive: Receive against a purchase order
Book what arrived: per PO line, the quantity and the storage unit it goes to (with the lot for lot-tracked products). An inspection plan for the product or vendor puts it in quarantine and opens an inspection task. Can't receive more than ordered. Needs 'Receive inventory'. Preview it first.
REST: POST /api/v1/purchase-orders/:id/receive · Permission: inventory:receive · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool purchase_orders_receive
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Purchase order id |
lines |
object[] | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
name |
string | null | yes | |
status |
string | yes | |
vendor |
string | null | yes | |
externalSystemId |
string | null | yes | |
lines |
object[] | yes |
customers.list: List customers
A factory's customers, who shipments go to: name, reference and ship-to address.
REST: GET /api/v1/customers · Permission: inventory:view · Effect: read · MCP: tool customers_list
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
externalRef |
string | null | yes | |
shipToAddress |
string | null | yes | |
isEightyOneCompany |
boolean | yes | Shipments arrive in their EightyOne stock |
shipments.list: List shipments
Shipments to customers, newest first: draft (being prepared), shipped or cancelled.
REST: GET /api/v1/shipments · Permission: inventory:view · Effect: read · MCP: tool shipments_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
status |
draft | shipped | cancelled |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
code |
string | yes | |
status |
string | yes | draft / shipped / cancelled |
customer |
object | null | yes | |
shipToAddress |
string | null | yes | |
trackingReference |
string | null | yes | |
notes |
string | null | yes | |
shippedAt |
string (date-time) | null | yes | |
partnerDeliveryState |
string | null | yes | For a customer that is an EightyOne company |
lines |
object[] | yes |
shipments.get: Get a shipment
A shipment with its lines.
REST: GET /api/v1/shipments/:id · Permission: inventory:view · Effect: read · MCP: tool shipments_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Shipment external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
code |
string | yes | |
status |
string | yes | draft / shipped / cancelled |
customer |
object | null | yes | |
shipToAddress |
string | null | yes | |
trackingReference |
string | null | yes | |
notes |
string | null | yes | |
shippedAt |
string (date-time) | null | yes | |
partnerDeliveryState |
string | null | yes | For a customer that is an EightyOne company |
lines |
object[] | yes |
shipments.create: Prepare a shipment
Draft a shipment to a customer: per line the SKU, quantity and the storage unit it ships from (and the lot for lot-tracked products). Nothing leaves stock until shipments_ship. Factories only. Needs 'Manage inventory'.
REST: POST /api/v1/shipments · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool shipments_create
Input
| Field | Type | Required | Description |
|---|---|---|---|
customerId |
string | yes | Customer external id (customers_list) |
lines |
object[] | yes | |
shipToAddress |
string | Defaults to the customer's | |
code |
string | ||
trackingReference |
string | ||
notes |
string |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
code |
string | yes | |
status |
string | yes | draft / shipped / cancelled |
customer |
object | null | yes | |
shipToAddress |
string | null | yes | |
trackingReference |
string | null | yes | |
notes |
string | null | yes | |
shippedAt |
string (date-time) | null | yes | |
partnerDeliveryState |
string | null | yes | For a customer that is an EightyOne company |
lines |
object[] | yes |
shipments.ship: Ship it
Confirm a draft shipment left: each line's goods come out of stock, written to the customer. For a customer that is an EightyOne company, the goods arrive in their transit. Refused if any line lacks the stock, names a lot that isn't available, or takes another customer's consigned stock. Needs 'Manage inventory'. Preview it first.
REST: POST /api/v1/shipments/:id/ship · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool shipments_ship
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Shipment external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
code |
string | yes | |
status |
string | yes | draft / shipped / cancelled |
customer |
object | null | yes | |
shipToAddress |
string | null | yes | |
trackingReference |
string | null | yes | |
notes |
string | null | yes | |
shippedAt |
string (date-time) | null | yes | |
partnerDeliveryState |
string | null | yes | For a customer that is an EightyOne company |
lines |
object[] | yes |
shipments.cancel: Cancel a draft shipment
Cancel a shipment that hasn't shipped. Nothing moves: a draft holds no stock. Needs 'Manage inventory'.
REST: POST /api/v1/shipments/:id/cancel · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool shipments_cancel
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Shipment external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
code |
string | yes | |
status |
string | yes | draft / shipped / cancelled |
customer |
object | null | yes | |
shipToAddress |
string | null | yes | |
trackingReference |
string | null | yes | |
notes |
string | null | yes | |
shippedAt |
string (date-time) | null | yes | |
partnerDeliveryState |
string | null | yes | For a customer that is an EightyOne company |
lines |
object[] | yes |
inventory_counts.list: List cycle counts
Cycle counts, newest first: which storage unit, status (draft, in_progress, completed = finalized and waiting to be reconciled, reconciled) and totals. inventory_counts_get shows the lines and discrepancies.
REST: GET /api/v1/inventory-counts · Permission: inventory:view · Effect: read · MCP: tool inventory_counts_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
status |
draft | in_progress | completed | reconciled |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes |
inventory_counts.get: Get a cycle count
A cycle count with its lines: expected (on hand by the system), counted, the discrepancy once finalized, and whether stock moved while it was open (a reason to recount rather than adjust).
REST: GET /api/v1/inventory-counts/:id · Permission: inventory:view · Effect: read · MCP: tool inventory_counts_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
inventory_counts.create: Start a cycle count
Open a count of one storage unit. It snapshots what the system expects there, and when the company has an inventory task type it also creates the count task operators fill in from the app. Needs 'Manage inventory'.
REST: POST /api/v1/inventory-counts · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool inventory_counts_create
Input
| Field | Type | Required | Description |
|---|---|---|---|
storageUnitId |
string | yes | Storage unit external id (storage_units_list) |
title |
string | The count task's title | |
dueDate |
string (date-time) | string (date) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
inventory_counts.record_lines: Record counted quantities
Add what someone counted to an open count, by SKU (and bin, lot or serial where it matters). Quantities add to what was already counted for that line, as in the dashboard. Then finalize it. Needs 'Manage inventory'.
REST: POST /api/v1/inventory-counts/:id/lines · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool inventory_counts_record_lines
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Count id |
lines |
object[] | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
inventory_counts.finalize: Finish a cycle count
Close counting: each line's expected quantity becomes what's on hand now, discrepancies are computed, and anything on hand the count never saw becomes a line counted 0. Nothing is posted to stock until it's reconciled. Needs 'Manage inventory'.
REST: POST /api/v1/inventory-counts/:id/finalize · Permission: inventory:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool inventory_counts_finalize
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
inventory_counts.reconcile: Post a cycle count to stock
Decide each line of a finalized count and post it. accepted: stock becomes the counted quantity; adjusted: becomes adjustedQuantity; ignored (and any line not listed): stock stays as the system has it. Every write-off needs an adjustment reasonCodeId (reason_codes_list kind adjustment). Needs 'Manage inventory' and 'Adjust inventory'. Preview it first: it lists each addition, write-off and bin move.
REST: POST /api/v1/inventory-counts/:id/reconcile · Permission: inventory:manage + inventory:adjust · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool inventory_counts_reconcile
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
decisions |
object[] | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
storageUnit |
object | null | yes | |
status |
string | yes | draft / in_progress / completed (finalized, awaiting reconciliation) / reconciled |
countType |
string | null | yes | |
totalExpected |
number | null | yes | |
totalCounted |
number | null | yes | |
taskId |
string | null | yes | The count task operators fill in, if any |
dueDate |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
reconciledAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
Production
work_orders.list: List work orders
The company's work orders, newest first, optionally by status. Use for ERP pull-sync or to see what production is working on.
REST: GET /api/v1/work-orders · Permission: production:view · Effect: read · MCP: tool work_orders_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
status |
draft | released | in_progress | completed | closed | cancelled |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Work order external id |
code |
string | yes | Human code, e.g. WO-1009 |
externalSystemId |
string | null | yes | Your (ERP) id for the order |
source |
string | yes | dashboard or erp |
status |
draft | released | in_progress | completed | closed | cancelled |
yes | |
product |
object | null | yes | |
quantity |
number | yes | |
uom |
string | null | yes | |
dueDate |
string (date-time) | null | yes | |
routing |
object | null | yes | |
releasedAt |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
work_orders.get: Get a work order
One work order with its operations (the traveler's tasks) and their status.
REST: GET /api/v1/work-orders/:externalId · Permission: production:view · Effect: read · MCP: tool work_orders_get
Input
| Field | Type | Required | Description |
|---|---|---|---|
externalId |
string | yes | Work order external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Work order external id |
code |
string | yes | Human code, e.g. WO-1009 |
externalSystemId |
string | null | yes | Your (ERP) id for the order |
source |
string | yes | dashboard or erp |
status |
draft | released | in_progress | completed | closed | cancelled |
yes | |
product |
object | null | yes | |
quantity |
number | yes | |
uom |
string | null | yes | |
dueDate |
string (date-time) | null | yes | |
routing |
object | null | yes | |
releasedAt |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
operations |
object[] | yes |
work_orders.release: Release a work order
Release a draft work order to the floor: one operation task per routing step, each on the only machine of its work center when there is just one, with the type's parameters pinned and later steps waiting for gates. Needs 'Release work orders'. Preview it with dryRun first: it lists the operations it creates.
REST: POST /api/v1/work-orders/:externalId/release · Permission: work_orders:release · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool work_orders_release
Input
| Field | Type | Required | Description |
|---|---|---|---|
externalId |
string | yes | Work order external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Work order external id |
code |
string | yes | Human code, e.g. WO-1009 |
externalSystemId |
string | null | yes | Your (ERP) id for the order |
source |
string | yes | dashboard or erp |
status |
draft | released | in_progress | completed | closed | cancelled |
yes | |
product |
object | null | yes | |
quantity |
number | yes | |
uom |
string | null | yes | |
dueDate |
string (date-time) | null | yes | |
routing |
object | null | yes | |
releasedAt |
string (date-time) | null | yes | |
completedAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
work_orders.upsert: Create or update a work order (ERP orders in)
Idempotent on externalSystemId: a new id creates a draft order; re-sending updates it while it is still a draft and is a no-op afterwards. Lands on the product's released routing when there is exactly one. Release it with work_orders.release.
REST: POST /api/v1/work-orders · Permission: production:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
externalSystemId |
string | yes | Your (ERP) id for the order: the upsert key |
productId |
integer | EightyOne product id (or give productSku) | |
productSku |
string | Product SKU (case-insensitive) | |
quantity |
number | ||
uom |
string | ||
dueDate |
string (date-time) | string (date) | ||
code |
string | Human code; defaults to the next WO-n |
Output
| Field | Type | Required | Description |
|---|---|---|---|
workOrder |
object | yes | |
created |
boolean | yes |
work_orders.batch_upsert: Create or update many work orders
Upsert up to 500 orders; each succeeds or fails on its own (results in input order).
REST: POST /api/v1/work-orders/batch · Permission: production:manage · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
orders |
any[] | yes | Each item is a work_orders.upsert input; an invalid item fails on its own |
Output
| Field | Type | Required | Description |
|---|---|---|---|
results |
object[] | yes |
Webhooks
webhooks.list: List webhooks
The company's webhook subscriptions.
REST: GET /api/v1/webhooks · Permission: api_keys:view · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip | |
isActive |
boolean | true | false |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
targetUrl |
string | yes | |
eventTypes |
string[] | yes | |
isActive |
boolean | yes | |
failureCount |
integer | yes | |
disabledAt |
string (date-time) | null | yes | Set when repeated failures switched the webhook off |
headers |
object | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
webhooks.event_types: List webhook event types
Every event a webhook can subscribe to, with what triggers it.
REST: GET /api/v1/webhooks/events · Permission: api_keys:view · Effect: read · MCP: via capabilities_call
Output
| Field | Type | Required | Description |
|---|---|---|---|
eventTypes |
object[] | yes |
webhooks.create: Create a webhook
Subscribe a URL to events. Deliveries are Standard Webhooks messages signed with EightyOne's Ed25519 key: verify them with the public keys at /api/v1/webhook-signing-keys. There is no secret to store.
REST: POST /api/v1/webhooks · Permission: webhooks:manage · Effect: write · Idempotency-Key: accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | yes | |
targetUrl |
string (uri) | yes | HTTPS endpoint; private and internal addresses are refused |
eventTypes |
task.status_changed | task.created | client.created | work_order.released | work_order.completed | downtime.started | downtime.ended | lot.created | stock.reorder_triggered | handoff.received | handoff.status_changed | handoff.declined | handoff.deleted | partner_delivery.incoming | partner_delivery.received | partner_delivery.shortfall | data_package.received[] |
yes | |
headers |
object | Extra headers sent with each delivery |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
targetUrl |
string | yes | |
eventTypes |
string[] | yes | |
isActive |
boolean | yes | |
failureCount |
integer | yes | |
disabledAt |
string (date-time) | null | yes | Set when repeated failures switched the webhook off |
headers |
object | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
verification |
object | yes | Verify each delivery's signature with EightyOne's public key |
webhooks.get: Get a webhook
One webhook subscription.
REST: GET /api/v1/webhooks/:id · Permission: api_keys:view · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
targetUrl |
string | yes | |
eventTypes |
string[] | yes | |
isActive |
boolean | yes | |
failureCount |
integer | yes | |
disabledAt |
string (date-time) | null | yes | Set when repeated failures switched the webhook off |
headers |
object | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
webhooks.update: Update a webhook
Change a webhook's name, URL, events, headers or active flag.
REST: PATCH /api/v1/webhooks/:id · Permission: webhooks:manage · Effect: write · Idempotency-Key: accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | ||
targetUrl |
string (uri) | ||
eventTypes |
task.status_changed | task.created | client.created | work_order.released | work_order.completed | downtime.started | downtime.ended | lot.created | stock.reorder_triggered | handoff.received | handoff.status_changed | handoff.declined | handoff.deleted | partner_delivery.incoming | partner_delivery.received | partner_delivery.shortfall | data_package.received[] |
||
isActive |
boolean | ||
headers |
object |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
targetUrl |
string | yes | |
eventTypes |
string[] | yes | |
isActive |
boolean | yes | |
failureCount |
integer | yes | |
disabledAt |
string (date-time) | null | yes | Set when repeated failures switched the webhook off |
headers |
object | null | yes | |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes |
webhooks.delete: Delete a webhook
Remove a webhook subscription.
REST: DELETE /api/v1/webhooks/:id · Permission: webhooks:manage · Effect: destructive · Idempotency-Key: accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
webhooks.delivery_logs: Webhook delivery log
Recent deliveries of one webhook with their status, response and timing.
REST: GET /api/v1/webhooks/:id/logs · Permission: api_keys:view · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
limit |
integer | Page size (1–100, default 50) | |
offset |
integer | Rows to skip | |
status |
pending | success | failed | retrying |
||
eventType |
task.status_changed | task.created | client.created | work_order.released | work_order.completed | downtime.started | downtime.ended | lot.created | stock.reorder_triggered | handoff.received | handoff.status_changed | handoff.declined | handoff.deleted | partner_delivery.incoming | partner_delivery.received | partner_delivery.shortfall | data_package.received |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
eventType |
string | yes | |
eventId |
string | yes | |
payload |
any | yes | |
status |
string | yes | |
attemptCount |
integer | yes | |
responseStatusCode |
integer | null | yes | |
responseBody |
string | null | yes | |
responseTimeMs |
integer | null | yes | |
errorMessage |
string | null | yes | |
nextRetryAt |
string (date-time) | null | yes | |
deliveredAt |
string (date-time) | null | yes | |
createdAt |
string (date-time) | yes |
webhooks.test: Send a test event
Queue a test delivery to THIS webhook only: a signed message of type webhook.test, to check your endpoint and its signature verification.
REST: POST /api/v1/webhooks/:id/test · Permission: webhooks:manage · Effect: write · Idempotency-Key: not accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
message |
string | yes | |
webhookId |
string | yes |
webhooks.retry_delivery: Retry a delivery
Re-send one logged delivery of this webhook.
REST: POST /api/v1/webhooks/:id/logs/:logId/retry · Permission: webhooks:manage · Effect: write · Idempotency-Key: not accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
logId |
integer | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
message |
string | yes | |
deliveryLogId |
integer | yes |
Partner network
handoffs.send: Send a task to a partner company
Hand one of your tasks to another EightyOne company (by its short name, or a partner subcontractor). The partner gets its own copy; your people come off the task. Goods can travel with it (items), and a data-request task carries the scopes it asks for.
REST: POST /api/v1/handoffs · Permission: handoffs:send · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool handoffs_send
Input
| Field | Type | Required | Description |
|---|---|---|---|
taskId |
string | yes | Your task's id |
recipientShortName |
string | ||
subContractorId |
integer | A subcontractor that is an EightyOne company | |
items |
object[] | ||
dataRequest |
object |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | yes | This company's own task (never the partner's) |
status |
string | yes | |
declinedReason |
string | null | yes | |
requestedItems |
object[] | yes | |
dataRequest |
object | null | yes | |
deliveries |
object[] | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes |
handoffs.list: List handoffs
Tasks you sent to, or received from, partner companies (newest first, up to 500).
REST: GET /api/v1/handoffs · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
direction |
incoming | outgoing | all |
||
state |
active | withdrawn | deleted |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | yes | This company's own task (never the partner's) |
status |
string | yes | |
declinedReason |
string | null | yes | |
requestedItems |
object[] | yes | |
dataRequest |
object | null | yes | |
deliveries |
object[] | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes |
handoffs.get: Get a handoff
One handoff from your side.
REST: GET /api/v1/handoffs/:id · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | yes | This company's own task (never the partner's) |
status |
string | yes | |
declinedReason |
string | null | yes | |
requestedItems |
object[] | yes | |
dataRequest |
object | null | yes | |
deliveries |
object[] | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes |
handoffs.timeline: Handoff timeline
What happened on a handoff, in order; your own people are named, the partner's are not.
REST: GET /api/v1/handoffs/:id/timeline · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
type |
string | yes | |
at |
string (date-time) | yes | |
by |
you | partner |
yes | |
actorName |
string | null | yes | Only your own people are named |
payload |
any | yes |
handoffs.decline: Decline a received handoff
Decline a task a partner sent you, with a reason they will see.
REST: POST /api/v1/handoffs/:id/decline · Permission: handoffs:send · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool handoffs_decline
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
reason |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | yes | This company's own task (never the partner's) |
status |
string | yes | |
declinedReason |
string | null | yes | |
requestedItems |
object[] | yes | |
dataRequest |
object | null | yes | |
deliveries |
object[] | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes |
handoffs.withdraw: Withdraw a sent handoff
Take back an active handoff you sent; the partner's copy is removed.
REST: DELETE /api/v1/handoffs/:id · Permission: handoffs:send · Effect: destructive · Idempotency-Key: accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
partner_deliveries.list: List partner deliveries
Goods sent to or received from partner companies, from your side.
REST: GET /api/v1/partner-deliveries · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
direction |
incoming | outgoing | all |
||
state |
in_transit | partially_received | shortfall | received | reversed | refused | unmapped | held | settled |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
kind |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | null | yes | |
handoffId |
string | null | yes | |
shipmentCode |
string | null | yes | |
returnOf |
string | null | yes | |
receivingStorageUnit |
object | null | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
partner_deliveries.get: Get a partner delivery
One delivery from your side.
REST: GET /api/v1/partner-deliveries/:id · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
kind |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | null | yes | |
handoffId |
string | null | yes | |
shipmentCode |
string | null | yes | |
returnOf |
string | null | yes | |
receivingStorageUnit |
object | null | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
partner_deliveries.receive: Receive a partner delivery
Book goods a partner sent you into stock, line by line (damaged quantities go to the bads bin), optionally reporting the rest missing.
REST: POST /api/v1/partner-deliveries/:id/receive · Permission: handoffs:send + inventory:receive · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool partner_deliveries_receive
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
lines |
object[] | ||
reportRestMissing |
boolean |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
kind |
string | yes | |
direction |
incoming | outgoing |
yes | |
state |
string | yes | |
partner |
object | yes | |
taskId |
string | null | yes | |
handoffId |
string | null | yes | |
shipmentCode |
string | null | yes | |
returnOf |
string | null | yes | |
receivingStorageUnit |
object | null | yes | |
linkActive |
boolean | yes | |
createdAt |
string (date-time) | yes | |
lines |
object[] | yes |
data_packages.list: List data packages
Traceability data packages you released to, or received from, partners.
REST: GET /api/v1/data-packages · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
role |
released | received |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
role |
string | yes | |
createdAt |
string (date-time) | yes | |
from |
any | yes | |
object |
any | yes |
data_packages.get: Get a data package
A data package's content, with short-lived links to its photos.
REST: GET /api/v1/data-packages/:id · Permission: handoffs:send · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
role |
string | yes | |
createdAt |
string (date-time) | yes | |
content |
any | yes | |
files |
object[] | yes |
Analytics
analytics.overview: Factory performance overview
Headline numbers for a window: total downtime, failures, average availability and OEE, and how many machines are monitored. unavailableMetrics names OEE factors with no source data yet. Start here, then drill into analytics.downtime / analytics.reliability.
REST: GET /api/v1/analytics/overview · Permission: insights:view · Effect: read · MCP: tool analytics_overview
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output
| Field | Type | Required | Description |
|---|---|---|---|
range |
object | yes | |
downtimeSeconds |
number | yes | |
downtimeHours |
number | yes | |
failures |
integer | yes | |
avgAvailability |
number | null | yes | 0–1 |
avgOee |
number | null | yes | 0–1 |
monitoredSsus |
integer | yes | |
unavailableMetrics |
string[] | yes |
analytics.downtime: Downtime by machine
Time each machine (SSU) spent DOWN or in MAINTENANCE in the window, most first, with how many times it entered that state. For the reasons, follow up with downtime_events.list (reason-coded stoppages) or storylines.ssu (the machine's story).
REST: GET /api/v1/analytics/downtime · Permission: insights:view · Effect: read · MCP: tool analytics_downtime
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | null | yes | SSU external id |
ssuName |
string | null | yes | |
category |
string | yes | DOWN or MAINTENANCE |
seconds |
number | yes | |
hours |
number | yes | |
transitions |
integer | yes | Times the machine entered this state |
analytics.reliability: Machine reliability (MTTR / MTBF)
Per machine: failures (entries into DOWN), mean time to repair and mean time between failures, in seconds, most failures first.
REST: GET /api/v1/analytics/reliability · Permission: insights:view · Effect: read · MCP: tool analytics_reliability
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | null | yes | SSU external id |
ssuName |
string | null | yes | |
failures |
integer | yes | |
mttrSeconds |
number | null | yes | |
mtbfSeconds |
number | null | yes |
analytics.oee: OEE by machine
Overall equipment effectiveness per machine: availability, performance and quality (0–1) with good / scrap quantities. A factor is null when its source data is missing (no routed work, no counts).
REST: GET /api/v1/analytics/oee · Permission: insights:view · Effect: read · MCP: tool analytics_oee
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | null | yes | SSU external id |
ssuName |
string | null | yes | |
plannedSeconds |
number | yes | |
downtimeSeconds |
number | yes | |
availability |
number | null | yes | |
performance |
number | null | yes | Can exceed 1 when the line beats its standards |
quality |
number | null | yes | |
goodQuantity |
number | yes | |
scrapQuantity |
number | yes | |
oee |
number | null | yes |
analytics.failure_pareto: Failure modes (Pareto)
What breaks most: completed failure-coded tasks grouped by problem code, most frequent first (top 25), with the machine that suffers each mode most.
REST: GET /api/v1/analytics/failure-pareto · Permission: insights:view · Effect: read · MCP: tool analytics_failure_pareto
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
problemCodeId |
integer | yes | |
code |
string | null | yes | |
label |
string | yes | |
count |
integer | yes | |
worstSsuName |
string | null | yes |
Machines
downtime_events.list: List machine stoppages
Individual downtime events (newest first, up to 500): when each machine stopped, for how long, and the reason code someone classified it with. Use it to explain the totals from analytics.downtime. Filter by machine and window; unclassifiedOnly lists stops still waiting for a reason.
REST: GET /api/v1/downtime-events · Permission: any member of the company · Effect: read · MCP: tool downtime_events_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | SSU external id | |
from |
string (date-time) | string (date) | Stops that started at or after this time | |
to |
string (date-time) | string (date) | Stops that started before this time | |
unclassifiedOnly |
boolean | true | false |
||
openOnly |
boolean | true | false |
Only machines still stopped |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
startedAt |
string (date-time) | yes | |
endedAt |
string (date-time) | null | yes | null while the machine is still stopped |
durationSeconds |
number | null | yes | |
source |
auto | manual |
yes | auto: detected from machine telemetry; manual: reported by a person |
reason |
object | null | yes | The downtime reason code, once someone classified the stop |
note |
string | null | yes |
downtime_events.classify: Give a stop its reason
Classify a machine stoppage with a downtime reason code (reason_codes_list, kind downtime), optionally with a note. Re-classifying replaces the reason. Find stops waiting for one with downtime_events_list and unclassifiedOnly.
REST: POST /api/v1/downtime-events/:id/classify · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool downtime_events_classify
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Downtime event id |
reasonCodeId |
integer | yes | A downtime reason code id |
note |
string |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
startedAt |
string (date-time) | yes | |
endedAt |
string (date-time) | null | yes | null while the machine is still stopped |
durationSeconds |
number | null | yes | |
source |
auto | manual |
yes | auto: detected from machine telemetry; manual: reported by a person |
reason |
object | null | yes | The downtime reason code, once someone classified the stop |
note |
string | null | yes |
downtime_events.open: Report a machine stopped
Record that a machine stopped now, for machines without telemetry (those report stops themselves). Close it with downtime_events_close when it runs again, and classify it with a reason. Needs 'Manage machine data'.
REST: POST /api/v1/downtime-events · Permission: machine_data:manage · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool downtime_events_open
Input
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | yes | SSU external id |
note |
string |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
startedAt |
string (date-time) | yes | |
endedAt |
string (date-time) | null | yes | null while the machine is still stopped |
durationSeconds |
number | null | yes | |
source |
auto | manual |
yes | auto: detected from machine telemetry; manual: reported by a person |
reason |
object | null | yes | The downtime reason code, once someone classified the stop |
note |
string | null | yes |
downtime_events.close: Report a machine running again
End a stoppage now. Closing one that already ended changes nothing. Needs 'Manage machine data'.
REST: POST /api/v1/downtime-events/:id/close · Permission: machine_data:manage · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool downtime_events_close
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Downtime event id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
startedAt |
string (date-time) | yes | |
endedAt |
string (date-time) | null | yes | null while the machine is still stopped |
durationSeconds |
number | null | yes | |
source |
auto | manual |
yes | auto: detected from machine telemetry; manual: reported by a person |
reason |
object | null | yes | The downtime reason code, once someone classified the stop |
note |
string | null | yes |
downtime_events.summary: Downtime by machine and reason
Recorded stoppages per machine in a window (default: the last 30 days), most stopped time first, each broken down by reason code: the direct answer to "which machines were down most, and why?". Counts only the part of each stop inside the window; a stop still open counts up to the window end. Complements analytics.downtime, which measures time in a DOWN / MAINTENANCE status.
REST: GET /api/v1/downtime-events/summary · Permission: any member of the company · Effect: read · MCP: tool downtime_events_summary
Input
| Field | Type | Required | Description |
|---|---|---|---|
from |
string (date-time) | string (date) | Window start (ISO 8601). Default: 30 days before to |
|
to |
string (date-time) | string (date) | Window end, exclusive (ISO 8601). Default: now |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
seconds |
number | yes | |
hours |
number | yes | |
stops |
integer | yes | |
openStops |
integer | yes | Stops not yet ended |
byReason |
object[] | yes |
reason_codes.list: List reason codes
The company's reason codes: why machines stop (downtime), failure problem / cause / remedy codes on maintenance tasks, scrap and stock-adjustment reasons.
REST: GET /api/v1/reason-codes · Permission: any member of the company · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
kind |
downtime | failure_problem | failure_cause | failure_remedy | scrap | adjustment |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
kind |
string | yes | |
code |
string | null | yes | |
label |
string | yes | |
parentId |
integer | null | yes | |
isActive |
boolean | yes |
meters.list: List machine meters
Usage meters on machines (run hours, strokes, cycles…) and their current readings. Usage-based maintenance rules open a task each time a meter advances by their interval. Filter by machine.
REST: GET /api/v1/meters · Permission: maintenance:view · Effect: read · MCP: tool meters_list
Input
| Field | Type | Required | Description |
|---|---|---|---|
ssuId |
string | SSU external id |
Output: { data, pagination }, each item:
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
key |
string | yes | |
name |
string | yes | |
uom |
string | null | yes | |
source |
manual | signal |
yes | signal: counted from machine data; manual: people enter readings |
currentValue |
number | yes |
meters.record_reading: Record a meter reading
Enter a meter's current total (not the change), as a technician reads it off the machine. It can open usage-based maintenance tasks: preview it with dryRun first to see which. Needs 'Manage maintenance'.
REST: POST /api/v1/meters/:id/readings · Permission: maintenance:manage · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool meters_record_reading
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | Meter id (meters_list) |
value |
number | yes | The meter's reading: its running total |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
ssuId |
string | yes | SSU external id |
ssuName |
string | null | yes | |
key |
string | yes | |
name |
string | yes | |
uom |
string | null | yes | |
source |
manual | signal |
yes | signal: counted from machine data; manual: people enter readings |
currentValue |
number | yes |
machine_catalog.search_makes: Search machine makes
Search the global catalog of machine manufacturers (e.g. 'Trumpf'). Use the existing spelling when it matches: everyone shares one catalog.
REST: GET /api/v1/machine-catalog/makes · Permission: any member of the company · Effect: read · MCP: tool machine_catalog_search_makes
Input
| Field | Type | Required | Description |
|---|---|---|---|
q |
string | Part of the make's name; empty lists common makes |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
name |
string | yes | |
matchType |
exact | prefix | contains | similar | null |
yes | similar = a 'did you mean' suggestion for a likely misspelling |
machine_catalog.search_models: Search machine models
Search the models of one make in the global catalog.
REST: GET /api/v1/machine-catalog/models · Permission: any member of the company · Effect: read · MCP: tool machine_catalog_search_models
Input
| Field | Type | Required | Description |
|---|---|---|---|
makeId |
integer | yes | Make id from machine_catalog.search_makes |
q |
string |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
id |
integer | yes | |
name |
string | yes | |
matchType |
exact | prefix | contains | similar | null |
yes | similar = a 'did you mean' suggestion for a likely misspelling |
machine_catalog.lookup_sku: Find a machine by SKU
The make and model registered for a model-level SKU / part number (not a serial number).
REST: GET /api/v1/machine-catalog/sku-lookup · Permission: any member of the company · Effect: read · MCP: via capabilities_call
Input
| Field | Type | Required | Description |
|---|---|---|---|
sku |
string |
Output: an array of
| Field | Type | Required | Description |
|---|---|---|---|
make |
object | yes | |
model |
object | yes |
Quality
ncrs.open: Open an NCR
Open a nonconformance report: a task of the company's NCR task type (Settings), linked to the task it was found on and carrying its machine and work order, with the affected lot or product recorded on it. A failed in-line check opens one by itself; use this for what people find. Disposition it with ncrs_disposition.
REST: POST /api/v1/ncrs · Permission: any member of the company · Effect: write · Idempotency-Key: accepted · Dry run: preview (checks the change and lists its effects, without making it) · MCP: tool ncrs_open
Input
| Field | Type | Required | Description |
|---|---|---|---|
title |
string | yes | What's wrong, in a line |
details |
string | What was found: measurements, quantities, how it was noticed | |
foundOn |
string | External id of the task it was found on (an operation or inspection): the NCR takes its machine and work order | |
ssuId |
string | SSU external id, when not taken from foundOn | |
workOrderId |
string | Work order external id, when not taken from foundOn | |
lotCode |
string | The affected lot | |
productSku |
string | The affected product | |
priorityId |
integer | ||
assigneeIds |
integer[] | Personnel ids |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Task external id |
title |
string | yes | |
details |
string | null | yes | |
status |
string | yes | |
startDate |
string (date-time) | null | yes | |
endDate |
string (date-time) | null | yes | |
dueDate |
string (date-time) | null | yes | |
priorityId |
integer | yes | |
typeId |
string | null | yes | Task type external id |
team |
object | null | yes | The team whose members see and take this task: its task type's team (change it on the type) |
ssuId |
string | null | yes | SSU external id |
externalSystemId |
string | null | yes | Your id for the task |
incompleteReason |
string | null | yes | |
declinedReason |
string | null | yes | |
isPartialCompletion |
boolean | yes | Completed in part; a follow-up task carries the rest |
handoffRole |
proxy | mirror | null |
yes | proxy: you sent it to a partner; mirror: a partner sent it to you |
problemCodeId |
integer | null | yes | Failure coding: what was wrong |
causeCodeId |
integer | null | yes | Failure coding: why |
remedyCodeId |
integer | null | yes | Failure coding: what fixed it |
createdAt |
string (date-time) | yes | |
updatedAt |
string (date-time) | yes | |
foundOn |
string | null | yes | |
lotCode |
string | null | yes | |
productSku |
string | null | yes |
ncrs.disposition: Disposition an NCR
Decide what happens to nonconforming material, once per NCR. use_as_is: recorded only. rework: creates a rework task (of reworkTaskTypeId, or the NCR's own type). scrap: moves quantity of the lot to the bads bin and blocks the lot. return: blocks the lot for return to the vendor. Needs 'Disposition NCRs'.
REST: POST /api/v1/ncrs/:id/disposition · Permission: ncr:disposition · Effect: write · Idempotency-Key: accepted · Dry run: supported · MCP: tool ncrs_disposition
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | The NCR's task external id |
disposition |
use_as_is | rework | scrap | return |
yes | |
lotCode |
string | The affected lot (scrap and return act on it) | |
quantity |
number | For scrap: how much of the lot | |
reworkTaskTypeId |
string | For rework: the task type's external id | |
notes |
string |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
disposition |
use_as_is | rework | scrap | return |
yes | |
lot |
object | null | yes | |
reworkTaskId |
string | null | yes | The rework task's external id |
Storylines
storylines.ssu: A machine's story
What happened on one machine (SSU) in a window (default: the last 7 days), as a chronological narrative: orders run, stops and their reasons, maintenance done, scrap and NCRs, meter readings, plus headline numbers. The best way to explain a machine's downtime.
REST: GET /api/v1/storylines/ssus/:id · Permission: maintenance:view · Effect: read · MCP: tool storylines_ssu
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | SSU external id |
from |
string (date-time) | string (date) | ||
to |
string (date-time) | string (date) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
subject |
object | yes | |
plotPoints |
object | yes | The story's headline numbers |
chapters |
object[] | yes |
storylines.work_order: A work order's story
The life of one work order as a narrative: release, each operation started and finished, what was consumed and produced, scrap, quality checks and NCRs, shipment; with lead time and yield.
REST: GET /api/v1/storylines/work-orders/:id · Permission: production:view · Effect: read · MCP: tool storylines_work_order
Input
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | Work order external id |
Output
| Field | Type | Required | Description |
|---|---|---|---|
subject |
object | yes | |
plotPoints |
object | yes | The story's headline numbers |
chapters |
object[] | yes |
Users
invitations.revoke: Revoke an invitation
Withdraw a pending invitation: it is revoked on WorkOS (the emailed link stops working) and the invitee is removed from the company, so the same address can be invited again.
Permission: users:manage · Effect: destructive · Idempotency-Key: not accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
userId |
string (uuid) | yes | The invited user's id (from the company's invitee list) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | yes |
invitations.resend: Resend an invitation
Email the invitee a new invitation with a fresh expiry, for one that expired or got lost. The previous invitation is revoked if it is still pending; the invitee keeps their role.
Permission: users:manage · Effect: write · Idempotency-Key: not accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
userId |
string (uuid) | yes | The invited user's id (from the company's invitee list) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
email |
string | yes | |
expiresAt |
string | yes |
Issues
issues.list: List reportable issues
The issues a member can report (e.g. Breakdown, Safety hazard). Each one is a form that files a task of its configured type on the chosen SSU.
Permission: any member of the company · Effect: read · MCP: no
Output
| Field | Type | Required | Description |
|---|---|---|---|
issues |
object[] | yes |
issues.get_form: Get an issue's report form
The fields of an issue's report form, in order, as configured in the form builder: the same form the issue's QR code opens.
Permission: any member of the company · Effect: read · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
issueId |
string | yes | The issue's id (from issues.list) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
id |
string | yes | |
name |
string | yes | |
items |
object[] | yes |
issues.upload_url: Get an upload URL for an issue photo
A short-lived URL to upload one photo for an issue report, stored where the QR flow stores its photos. PUT the file to it, then submit the URL without its query string as the answer.
Permission: any member of the company · Effect: write · Idempotency-Key: not accepted · Dry run: not supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
issueId |
string | yes | The issue's id (from issues.list) |
fileName |
string | yes | |
contentType |
string | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
uploadUrl |
string | yes |
issues.report: Report an issue
File an issue report on an SSU, as its QR code would: creates a task of the issue's type with the answers attached, and applies any SSU status the form's machine-status fields set.
Permission: any member of the company · Effect: write · Idempotency-Key: not accepted · Dry run: supported · MCP: no
Input
| Field | Type | Required | Description |
|---|---|---|---|
issueId |
string | yes | The issue's id (from issues.list) |
ssuId |
string | yes | The SSU's id |
answers |
object[] | yes |
Output
| Field | Type | Required | Description |
|---|---|---|---|
taskId |
string | yes |
Commissioning
config.export: Export the factory setup
The company's setup as a factory spec: settings, SSU statuses, reason codes, work centers, sites with their storage units and SSU trees, warehouses, product categories, vendors, products by SKU with their vendors, recipe and stock policies, parameter sets, task types with their forms, SLAs and gates, routings, per-machine signals, meters, condition rules and spare parts, flows, issue reports, inspection plans, and people (permission groups, roles, teams, skills, existing people by email, subcontractors). Everything is referenced by name, so the spec can be applied to another company as a template. Start here before changing setup: edit the export, then config.plan and config.apply.
REST: GET /api/v1/config/export · Permission: any member of the company · Effect: read · MCP: tool config_export
Output
| Field | Type | Required | Description |
|---|---|---|---|
version |
number | yes | |
settings |
object | ||
ssuStatuses |
object[] | ||
reasonCodes |
object[] | ||
workCenters |
object[] | ||
sites |
object[] | ||
warehouses |
object[] | ||
productCategories |
object[] | ||
vendors |
object[] | ||
products |
object[] | Products by SKU, with their vendors, recipe and stock policies. No prices or costs | |
parameterSets |
object[] | ||
taskTypes |
object[] | Kinds of work, each with its form, SLAs and gates. People (default assignee, skills) come later | |
routings |
object[] | Step sequences that work orders follow | |
machineData |
object[] | Per machine: signals, meters, condition rules and spare parts | |
flows |
object[] | Automations: a task's status change creates the next task | |
issues |
object[] | Issue reports people can file (from the app or a QR code) | |
permissionGroups |
object[] | ||
roles |
object[] | What people are; each role grants one permission group | |
teams |
object[] | ||
skills |
object[] | ||
people |
object[] | Users already in the company, by email: their roles, teams, skills. Specs never invite | |
subcontractors |
object[] | ||
inspectionPlans |
object[] | Which receipts or products must be inspected, and how | |
guidance |
object[] | What the company tells every AI agent: company-wide and on specific machines, work centers, products, task types |
config.validate: Validate a factory spec
Checks a spec beyond its schema: duplicate names or SKUs, references to statuses, work centers, reason codes, storage, categories, vendors, SKUs, task types, parameter sets or permission groups that don't exist, ambiguous names, a product both bought and made, gates naming fields the form doesn't have. Doesn't change anything.
REST: POST /api/v1/config/validate · Permission: any member of the company · Effect: read · MCP: tool config_validate
Input
| Field | Type | Required | Description |
|---|---|---|---|
spec |
object | yes | The factory spec (export one with config.export to see the shape) |
Output
| Field | Type | Required | Description |
|---|---|---|---|
valid |
boolean | yes | |
problems |
object[] | yes |
config.plan: Preview applying a factory spec
What config.apply would do, change by change: create, update (with each field's current and new value), unchanged, and extra (in the company but not in the spec). Doesn't change anything. Show this plan to the user before applying.
REST: POST /api/v1/config/plan · Permission: any member of the company · Effect: read · MCP: tool config_plan
Input
| Field | Type | Required | Description |
|---|---|---|---|
spec |
object | yes | The factory spec (export one with config.export to see the shape) |
prune |
boolean | true | false |
Also remove what the spec leaves out of the sections it includes. Records with history (sites, SSUs, reason codes, products) are deactivated, not deleted; vendors, categories, task types and routings are removed only when nothing uses them; parameter sets are never removed. REST only |
Output
| Field | Type | Required | Description |
|---|---|---|---|
valid |
boolean | yes | |
problems |
object[] | yes | |
summary |
object | yes | |
changes |
object[] | yes |
config.apply: Apply a factory spec
Converges the company's setup to the spec, through the same rules as the dashboard; every change is audited. Safe to re-run: unchanged items are skipped. Not one transaction: if a change fails, the ones before it stay and the result says where it stopped; fix the cause and apply again. Always run config.plan first and get the user's go-ahead.
REST: POST /api/v1/config/apply · Permission: settings:manage or task_types:manage or clients:manage or inventory:manage or products:manage or production:manage or mobile_builder:manage or machine_data:manage or maintenance:manage or flows:manage or quality:manage or permissions:manage or personnel:manage or subcontractors:manage or ai_guidance:manage · Effect: write · Idempotency-Key: accepted · Dry run: not supported · MCP: tool config_apply
Input
| Field | Type | Required | Description |
|---|---|---|---|
spec |
object | yes | The factory spec (export one with config.export to see the shape) |
prune |
boolean | true | false |
Also remove what the spec leaves out of the sections it includes. Records with history (sites, SSUs, reason codes, products) are deactivated, not deleted; vendors, categories, task types and routings are removed only when nothing uses them; parameter sets are never removed. REST only |
Output
| Field | Type | Required | Description |
|---|---|---|---|
complete |
boolean | yes | |
applied |
object[] | yes | |
failed |
object | ||
skipped |
integer | yes | Changes not attempted after a failure |
