Attach a workflow to a chat, or move the chat one stage along it — the same action a team member takes from the inbox sidebar, under the same rules:
- Attach: pass
workflowId(fromGET /workflows/{organisationId}) and nostageId. The chat lands on the workflow's initial stage (outcome: attached). If it is already on this workflow nothing changes (unchanged). - Move: pass
workflowId+stageId. The move must be ONE allowed transition from the current stage (seeavailableTransitionsonGET …/workflow); otherwise 409ILLEGAL_TRANSITION. When the chat is not on the workflow yet, it is attached first and then moved if the stage is one hop from the initial stage (attached); if not reachable in one hop the chat stays on the initial stage and the outcome ispartialwithcode: STAGE_UNREACHABLE. - Finish: moving into a
finalstage finishes the run. Where the workflow requires a disposition first, the move is refused with 409DISPOSITION_REQUIREDand nothing is written. Where the workflow or organisation resolves chats on finish, the chat is marked resolved too — unlesskeepChatOpen: true. - Finished runs: a chat whose run already finished answers
outcome: finishedand does not change, unlessonFinished: "restart"starts a new run from the initial stage (restarted; on a resolved chat this reopens it where the resolve-on-finish rule applies). - Switch workflows: a chat that is live on a DIFFERENT workflow is refused with 409
ACTIVE_WORKFLOW_CONFLICT(the body listsactiveWorkflows). PassreplaceActive: trueto close that run and switch; the closed run is kept in the history as "Superseded by workflow change via API". The other run is closed after the switch succeeds — except when the target is a final stage, where it is closed first so the closing rules can resolve the chat; a refusal after that point (e.g.DISPOSITION_REQUIRED) listsreplacedWorkflowIdsin the error body.
Every attach fires the chat.workflow_started webhook with trigger: "API"; every move or restart fires chat.state_changed — exactly as a team member's change does, so automations and Meta lead signals react to it too. The stage history attributes the change to the API user your token belongs to. remarks (max 200 characters) is stored with the change.
One hop per call: to move several stages, call once per stage. Concurrent updates to the same chat are serialised; a call that finds another update in progress answers 409 WORKFLOW_BUSY — retry after a moment.
Requires CRM_ADMIN, ACCOUNT_OWNER, or CRM_BOT.
| Time | Status | User Agent | |
|---|---|---|---|
Retrieving recent requests… | |||
400Validation failed (workflowId not a UUID, stageId/remarks too long, unknown onFinished), the workflow has no initial stage (NO_START_STAGE), or the underlying step rejected the request (REJECTED).
401Unauthorized
403Forbidden
404Not found in your organisation — code is CHAT_NOT_FOUND, WORKFLOW_NOT_FOUND or STAGE_NOT_FOUND.
409Refused — code is ILLEGAL_TRANSITION (not an allowed move from the current stage), DISPOSITION_REQUIRED (capture a chat disposition first), ACTIVE_WORKFLOW_CONFLICT (live on another workflow; body lists activeWorkflows), WORKFLOW_INACTIVE, CURRENT_STAGE_UNKNOWN (the chat sits on a stage that was deleted from the workflow) or WORKFLOW_BUSY (another update to this chat is in progress — retry).
429Too many requests
503LOCK_UNAVAILABLE — the lock service is unavailable; nothing was changed. Retry later.
