Guides
An interaction step in a workflow spec suspends the run when the engine
reaches it and creates a pending interaction for the targeted reviewer.
This guide shows how to start such a run, detect the suspension, fetch
the interaction, and submit the response that resumes execution — for
any backend service that needs to gate workflow progress on human input.
Before you start
- You have a Mobius API key exported as
MOBIUS_API_KEY. See Create an API key if you do not. - Your project handle and API base URL are exported as
PROJECTandMOBIUS_BASE_URL. - Export
REVIEWER_IDas the Mobius user ID of the person who will respond to the interaction.
Walkthrough
-
Start a run with an inline
interactionstep by callingPOST /v1/projects/{project}/runs. The step declares the interaction type, message, target user, and timeout.curl -X POST "$MOBIUS_BASE_URL/v1/projects/$PROJECT/runs" \ -H "Authorization: Bearer $MOBIUS_API_KEY" \ -H "Content-Type: application/json" \ -d "{ \"spec\": { \"name\": \"doc-approval\", \"steps\": [{ \"name\": \"get-approval\", \"interaction\": { \"type\": \"approval\", \"message\": \"Approve document for publication?\", \"target\": { \"type\": \"user\", \"id\": \"$REVIEWER_ID\" }, \"timeout\": \"24h\", \"spec\": { \"mode\": \"confirm\" } } }] } }"Returns a run with
status: queued. Capture theidfield asRUN_ID. -
Subscribe to the run's event stream with
GET /v1/projects/{project}/runs/{id}/events. Each SSE frame carries{type, run_id, seq, timestamp, data}. Close the stream when you see arun_updatedframe withdata.status: suspended.curl --no-buffer \ "$MOBIUS_BASE_URL/v1/projects/$PROJECT/runs/$RUN_ID/events" \ -H "Authorization: Bearer $MOBIUS_API_KEY" -
List the pending interaction for the run with
GET /v1/projects/{project}/interactions, filtering byrun_idandstatus=pending. Capture the interactionidasINTERACTION_ID.curl "$MOBIUS_BASE_URL/v1/projects/$PROJECT/interactions?run_id=$RUN_ID&status=pending" \ -H "Authorization: Bearer $MOBIUS_API_KEY"Returns
{ "items": [ { "id": "...", "type": "approval", "status": "pending", ... } ] }. -
Submit the reviewer's response with
POST /v1/projects/{project}/interactions/{id}/respond. Completing a run-backed interaction automatically delivers the signal that resumes the suspended run.curl -X POST \ "$MOBIUS_BASE_URL/v1/projects/$PROJECT/interactions/$INTERACTION_ID/respond" \ -H "Authorization: Bearer $MOBIUS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "value": true, "comment": "Looks good." }'Returns the interaction with
status: completed. The run re-entersqueuedand continues.
Follow-ups
- Deliver a signal directly to a suspended run (bypassing the interaction
layer) with
POST /v1/projects/{project}/runs/{id}/signals. - Route to a group by setting
target.type: "group". Addrequire_all: trueto require every group member to respond before the interaction completes. - Retrieve any interaction by ID with
GET /v1/projects/{project}/interactions/{id}. - Create a standalone interaction (not attached to any run) with
POST /v1/projects/{project}/interactions.
Troubleshooting
itemsis empty in step 3: the run has not yet reached the interaction step. Confirm you received arun_updatedframe withstatus: suspendedin step 2 before listing interactions.409onrespondToInteraction: the interaction is already completed or has expired. Fetch its current state withGET /v1/projects/{project}/interactions/{id}and check thestatusfield.401on any call: the API key is missing or revoked. Re-issue with Create an API key and re-exportMOBIUS_API_KEY.
See also
- Runs — run status lifecycle and the
suspendedstate. - Redoc reference: interactions — full interaction schema and all operations.
- Redoc reference: runs — run schemas, signal delivery, and the event stream.