RaabtaHQ
Start a run

Start a run

POST/api/v1/runs

scope runs:startIdempotentCosts 10 rate-limit units

Asks an assistant to do something, and returns immediately with a queued run — the work happens in the background, so poll GET /runs/{id} or subscribe to the assistant.run_completed webhook rather than waiting on this call. A run bound to a contact or conversation may reply on your channels. One run at a time per conversation: starting a second returns 409 conflict with reason: run_already_active. Refused with 402 when the account’s monthly AI budget is exhausted, and with 422 assistant_disabled when the assistant is switched off.

Body

application/json
NameTypeDescription
assistant_idrequired
string (uuid)The assistant to run
goalrequired
stringWhat you want it to do, in plain language
contact_idoptional
string (uuid) | nullThe contact this is about. Its most recent conversation is used if there is one
conversation_idoptional
string (uuid) | nullReply in this specific thread instead of resolving one from the contact
Request
curl -X POST "https://your-crm.example.com/api/v1/runs" \
  -H "Authorization: Bearer $RAABTA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b4d-4c5e-8f7a-9b0c1d2e3f4a" \
  -d '{
    "assistant_id": "8f2c1d3e-4a5b-4c6d-9e0f-1a2b3c4d5e6f",
    "goal": "Follow up with Ayesha about her missed appointment and offer to rebook.",
    "contact_id": "9d7e4c11-5a2b-4f7c-8e3d-2a1b0c9d8e7f"
  }'
Response · 202 Accepted
{
  "data": {
    "id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
    "assistant_id": "8f2c1d3e-4a5b-4c6d-9e0f-1a2b3c4d5e6f",
    "assistant": {
      "id": "8f2c1d3e-4a5b-4c6d-9e0f-1a2b3c4d5e6f",
      "name": "Front desk",
      "color": "#0ea5e9"
    },
    "status": "queued",
    "goal": "Follow up with Ayesha about her missed appointment and offer to rebook.",
    "trigger": {
      "type": "manual",
      "trigger_id": null,
      "trigger_name": null,
      "event_key": null
    },
    "contact_id": "9d7e4c11-5a2b-4f7c-8e3d-2a1b0c9d8e7f",
    "conversation_id": "1c2d3e4f-5a6b-4c7d-8e9f-0a1b2c3d4e5f",
    "parent_run_id": null,
    "root_run_id": "3f9a1c2e-5b7d-4e8f-9a0b-1c2d3e4f5a6b",
    "depth": 0,
    "result": null,
    "tick_count": 0,
    "cost_usd": 0,
    "error_code": null,
    "error_message": null,
    "started_at": "2026-09-02T09:00:00.000Z",
    "ended_at": null,
    "created_at": "2026-09-02T09:00:00.000Z"
  }
}

Response

Wrapped in { data: … }
NameTypeDescription
idrequired
string (uuid)Run id
assistant_idrequired
string (uuid)The assistant running
assistantrequired
object | nullThe assistant, or null if it has since been deleted
assistant.idrequired
string (uuid)Assistant id
assistant.namerequired
stringAssistant name
assistant.colorrequired
string | nullAccent colour
statusrequired
string (enum)Where the run is in its lifecyclequeuedrunningwaiting_replywaiting_approvalwaiting_childrencompletedfailedcancelled
goalrequired
stringWhat this run was asked to do
triggerrequired
objectWhere the run came from
trigger.typerequired
stringOne of manual, inbound_message, schedule, event, webhook or delegation
trigger.trigger_idrequired
string (uuid) | nullThe assistant trigger, when one fired it
trigger.trigger_namerequired
string | nullThat trigger name
trigger.event_keyrequired
string | nullThe event key, for an event trigger
contact_idrequired
string (uuid) | nullThe contact it concerns, if any
conversation_idrequired
string (uuid) | nullThe thread it may answer in, if any
parent_run_idrequired
string (uuid) | nullSet when this is a sub-agent of another run
root_run_idrequired
string (uuid) | nullThe top of the delegation tree
depthrequired
integer0 for a root run
resultrequired
object | nullPresent once the run has ended
result.outcomerequired
string | nullHow it ended, in one word
result.summaryrequired
string | nullOne line on what happened
tick_countrequired
integerModel turns this run has taken
cost_usdrequired
numberBilled AI spend attributed to this run
error_coderequired
string | nullMachine code when the run failed
error_messagerequired
string | nullOperator-facing failure text
started_atrequired
string (date-time)When the run was created
ended_atrequired
string (date-time) | nullWhen it reached a terminal status
created_atrequired
string (date-time)When the row was written

Errors

StatusCodeWhen
400bad_requestThe request could not be parsed: malformed JSON, an invalid cursor, or a query parameter of the wrong shape.
400validation_errorThe body or query failed validation. `details` lists each failing field with a `path` and a `message`.
401unauthorizedNo usable API key: the Authorization header is missing or malformed, or the key is unknown, revoked or expired. The three are deliberately indistinguishable.
402plan_limit_reachedThe account has reached a plan limit for this resource. `details[0].limit` is the cap; ask the account owner to raise it.
403forbiddenThe key is valid but lacks the scope this endpoint requires, or the request came from an address outside the key’s IP allowlist. The message says which.
403account_suspendedThe account this key belongs to is suspended. Rotating the key will not help; contact support.
404not_foundNo such resource in this account. A resource that exists in another account also returns this.
409conflictThe request conflicts with current state: a duplicate phone number on create, an invalid state transition, or an idempotent request that is still in flight.
422unprocessableThe request was well-formed but cannot be carried out. `reason` is a stable string saying why (for example `outside_window` or `stage_not_in_pipeline`).
429rate_limitedThe per-key budget, or the per-IP budget for failed authentication, is exhausted. Honour `Retry-After` before retrying.
500internalSomething failed on our side. Safe to retry with the same Idempotency-Key; quote `request_id` if it persists.