API reference

Assistants

The Ask assistant, and the setup assistant that plans and builds agents after your approval.

The platform has two built-in assistants. Ask answers questions about your account in plain language. The setup assistant takes a description of what you want (or a filled-in template), proposes a plan made of API operations, and runs it only after you approve. The setup assistant guide walks through a full session.

Both need an AI backend that the operator configures, and both are unavailable without one. The endpoints then say so instead of failing: Ask answers with provider: "none", and the setup assistant reports available: false.

OperationMethod and pathMinimum role
Ask a questionPOST /assistants/askmember
List Ask conversationsGET /assistants/ask/sessionsviewer
Get setup assistant statusGET /assistants/setup/statusviewer
List templatesGET /assistants/setup/templatesviewer
Get a templateGET /assistants/setup/templates/{template_id}viewer
Create a brief from a templatePOST /assistants/setup/templates/{template_id}/briefmember
Create a sessionPOST /assistants/setup/sessionsmember
List sessionsGET /assistants/setup/sessionsviewer
Get a sessionGET /assistants/setup/sessions/{session_id}viewer
Send a messagePOST /assistants/setup/sessions/{session_id}/messagesmember
Approve or reject a planPOST /assistants/setup/sessions/{session_id}/plan/{plan_id}member

Ask

Ask a question

POST /assistants/ask

Answers a question with a language model that is given a short summary of the account: the wallet balance, agent names, call counts by status and phone numbers. It cannot change anything.

The model used is the account's own OpenAI-compatible provider key if one is saved (see Providers), otherwise the platform's own language model if the operator runs one. With neither, the reply is null.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
messagesbodyarrayyes1 to 40 messages, oldest first. The conversation so far, ending with the question.
messages[].rolebodystringyesuser or assistant.
messages[].contentbodystringyesUp to 4000 characters.

Request

bash
curl -X POST https://api.sevennadi.si/assistants/ask \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"messages": [{"role": "user", "content": "How many of my calls completed?"}]}'

Response 200 OK

json
{"reply": "12 of your calls have the status completed.", "provider": "openai"}

provider names where the answer came from: the account's provider, or local for the platform's own model. Without any model the response is:

json
{"reply": null, "provider": "none"}

The reply text is illustrative; it comes from a language model and can be wrong.

Errors

StatusMessage
400messages must be a non-empty list (at most 40)
400each message needs role user|assistant and string content
400messages are limited to 4000 characters
502The LLM provider failed: ... followed by the provider's error. Addresses of the platform's own servers are replaced with <internal address>.

List Ask conversations

GET /assistants/ask/sessions

Lists earlier Ask conversations. Conversations are not stored yet, so the list is always empty; the dashboard keeps the current conversation in the browser.

Auth: API key or session token. Role: viewer and up.

No parameters.

Request

bash
curl https://api.sevennadi.si/assistants/ask/sessions \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"sessions": []}

Limitation: Ask conversations are not saved on the server. This route exists so that clients have a stable place to read them from once they are.

Setup assistant

A setup session is a conversation. You send a message, the assistant reads your account through the API and may propose a plan: an ordered list of API operations such as "create this agent" or "add these dispositions". Nothing in a plan runs until you approve it. Operations that delete something or spend money are flagged and must each be confirmed by name.

The assistant acts with the token you called it with, so it can do exactly what you can do and nothing more.

Backends and availability

The operator chooses the backend. GET /assistants/setup/status reports it as provider:

providerMeaning
claude_codeA local Claude Code installation on the operator's server.
anthropic_apiThe Anthropic API, with the operator's API key.
fakeA scripted demo that always follows the same steps. For tests; it can only be selected where the operator allows it.
noneNo backend is configured, or the operator switched the assistant off. The assistant is unavailable.

Limits

  • 20 messages per account per hour (operator-configured).
  • A message or brief is at most 16,000 characters.
  • A plan has at most 20 operations, and one run makes at most 40 tool calls (both operator-configured).
  • One run at a time per session. A session that has been running for more than 15 minutes is treated as stale and accepts new requests again.
  • A message can be a billable event. Its price is the operator's (setup_assistant ledger entries); the shipped default is free.

Get setup assistant status

GET /assistants/setup/status

Says which backend is in use and whether it is available.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
backendquerystringnofake asks about the scripted demo. It is honoured only where the operator allows it.

Request

bash
curl https://api.sevennadi.si/assistants/setup/status \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{"provider": "anthropic_api", "label": "Claude API", "available": true, "hint": null}

When it is unavailable, available is false, provider is none (or the configured backend that is not usable) and hint says what the operator needs to configure.

List templates

GET /assistants/setup/templates

Lists the ready-made use cases. A template is a form plus a blueprint; filling in the form produces a brief you send as the first message of a session.

Auth: API key or session token. Role: viewer and up.

Request

bash
curl https://api.sevennadi.si/assistants/setup/templates \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK (one of several)

json
{
  "templates": [
    {
      "id": "card-payment-reminder",
      "industry": "Banking & cards",
      "name": "Credit-card payment reminder",
      "summary": "Reminds card holders of the amount due, confirms identity on the keypad and records a promise-to-pay date.",
      "direction": "outbound",
      "tags": ["collections", "regulated", "keypad", "promise to pay"]
    }
  ]
}

direction is inbound, outbound or both.

Get a template

GET /assistants/setup/templates/{template_id}

Returns one template in full: its form fields, with the voice and language choices resolved at request time, the field groups, and the blueprint the assistant builds from.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
template_idpathstringyesA template id from the list.

Request

bash
curl https://api.sevennadi.si/assistants/setup/templates/card-payment-reminder \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK (shortened)

json
{
  "id": "card-payment-reminder",
  "industry": "Banking & cards",
  "name": "Credit-card payment reminder",
  "summary": "Reminds card holders of the amount due, confirms identity on the keypad and records a promise-to-pay date.",
  "direction": "outbound",
  "tags": ["collections", "regulated", "keypad", "promise to pay"],
  "fields": [
    {
      "key": "company_name",
      "label": "Company name",
      "type": "text",
      "group": "Your business",
      "required": true,
      "placeholder": "Example Bank",
      "help": "The name the agent says it is calling from.",
      "default": null
    }
  ],
  "groups": ["Your business", "Agent persona", "Calling rules", "Your systems", "Script and rules"],
  "blueprint": {},
  "brief_template": "..."
}

Each field has key, label, type, group, required, placeholder, help and default. Field types are text, textarea, select, multiselect, toggle, number, time, phone and url. Choice fields also have options (a list of {"value", "label"}), and number fields may have min and max. The placeholder and help texts above are illustrative.

Errors

StatusMessage
404Template not found

Create a brief from a template

POST /assistants/setup/templates/{template_id}/brief

Validates the form values and returns the brief: the full request text for the assistant, built from the template and your answers. Nothing is created. Send the brief as the first message of a new session.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
template_idpathstringyesA template id.
valuesbodyobjectyesOne entry per field key. Required fields must be present; unknown keys are refused.

Request

bash
curl -X POST https://api.sevennadi.si/assistants/setup/templates/card-payment-reminder/brief \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"values": {"company_name": "Example Bank", "agent_name": "Neha", "voice": "VOICE_OPTION_VALUE", "call_start": "10:00", "call_end": "18:00"}}'

The values shown are a subset; read the template first to see every required field and the allowed options.

Response 200 OK (the brief text is shortened and illustrative)

json
{
  "brief": "Set up a credit-card payment reminder agent for Example Bank ...",
  "title": "Credit-card payment reminder: Example Bank",
  "template_id": "card-payment-reminder"
}

Errors

A validation failure has the usual error and message, plus an errors object with one message per field key. message is the first problem, with the field's label.

json
{
  "error": 400,
  "message": "Company name is required",
  "errors": {"company_name": "is required", "call_start": "is required"}
}
StatusMessage
400<Field label> is required
400<Field label> is limited to 160 characters (the limit depends on the field)
400<Field label> is not one of the options
400<Field label> must be a time such as 10:00
400<Field label> must be a phone number with country code, such as +919812345678
400<Field label> must be a web address starting with https:// or http://
400<key> is not a field of this template
400The details are too long for one request; shorten the longer answers
404Template not found

Create a session

POST /assistants/setup/sessions

Starts a setup session and reports the backend it will use. If the assistant is unavailable, no session is created and session_id is null.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
titlebodystringnoUp to 200 characters. If empty, the first message becomes the title.
template_idbodystringnoThe template this session starts from.
backendbodystringnoOnly fake is accepted, to request the scripted demo. The server picks the real backend.

The body may be omitted.

Request

bash
curl -X POST https://api.sevennadi.si/assistants/setup/sessions \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"title": "Payment reminders", "template_id": "card-payment-reminder"}'

Response 201 Created

json
{
  "session_id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
  "provider": "anthropic_api",
  "label": "Claude API",
  "available": true,
  "hint": null
}

When the assistant is unavailable, the status is still 201:

json
{"session_id": null, "provider": "none", "label": "Not available", "available": false, "hint": "..."}

Errors

StatusMessage
400backend may only be 'fake' (the scripted demo); the server picks the real one
400template_id is not a known template

List sessions

GET /assistants/setup/sessions

Lists the account's 50 most recently updated sessions.

Auth: API key or session token. Role: viewer and up.

Request

bash
curl https://api.sevennadi.si/assistants/setup/sessions \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK

json
{
  "sessions": [
    {
      "id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
      "title": "Payment reminders",
      "status": "awaiting_approval",
      "backend": "anthropic_api",
      "updated_at": "2026-10-13T09:05:12.345678+00:00"
    }
  ]
}

status is idle, running or awaiting_approval. Here updated_at is an ISO 8601 timestamp with fractional seconds and a UTC offset, unlike the ...Z form used elsewhere.

Get a session

GET /assistants/setup/sessions/{session_id}

Returns a session with its transcript and plans. Use it to restore a conversation after a page reload or a dropped stream.

Auth: API key or session token. Role: viewer and up.

ParameterInTypeRequiredDescription
session_idpathstring (UUID)yesThe session's id.

Request

bash
curl https://api.sevennadi.si/assistants/setup/sessions/e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9 \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"

Response 200 OK (shortened)

json
{
  "id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
  "title": "Payment reminders",
  "template_id": "card-payment-reminder",
  "status": "awaiting_approval",
  "backend": {"provider": "anthropic_api", "label": "Claude API"},
  "transcript": [
    {"type": "user", "text": "Set up a payment reminder agent", "at": "2026-10-13T09:04:00Z"},
    {"type": "assistant", "text": "I'll check your account first.", "at": "2026-10-13T09:04:03Z"},
    {"type": "tool", "name": "get_account", "summary": "", "ok": true},
    {"type": "plan", "plan_id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "title": "Payment reminder agent", "operations": [], "at": "2026-10-13T09:05:12Z"}
  ],
  "plans": [
    {
      "id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d",
      "session_id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9",
      "status": "pending",
      "title": "Payment reminder agent",
      "summary": "Creates one agent and its dispositions.",
      "operations": [
        {
          "id": "op1",
          "method": "POST",
          "path": "/v2/agent",
          "body": {},
          "description": "Create the payment reminder agent",
          "label": "Create agent",
          "flags": [],
          "encoding": "json"
        }
      ],
      "results": null,
      "created_at": "2026-10-13T09:05:12Z",
      "decided_at": null,
      "decision_note": null
    }
  ],
  "tool_calls": 4,
  "created_at": "2026-10-13T09:03:50Z",
  "updated_at": "2026-10-13T09:05:12Z"
}

The texts and the label and encoding values in the example are illustrative.

FieldMeaning
transcript[].typeuser, assistant, tool, plan, decision, results or error.
plans[].statuspending, superseded (a newer plan replaced it), approved, rejected, executed or failed.
plans[].operations[].idop1, op2, ... in the order they run. A later operation can refer to an earlier one's response, for example {{op1.agent_id}} in its path or body.
plans[].operations[].flagsEmpty, or any of destructive and spends_money. Flagged operations need explicit confirmation.
plans[].resultsAfter the plan ran: one result per operation. See the operation event below.

Errors

StatusMessage
404Session not found

Send a message

POST /assistants/setup/sessions/{session_id}/messages

Sends your message to the assistant and streams its work back as server-sent events. The response stays open until the assistant has finished this turn.

Auth: API key or session token. Role: member and up.

ParameterInTypeRequiredDescription
session_idpathstring (UUID)yesThe session's id.
contentbodystringyesYour request, or a brief from a template. Up to 16,000 characters.

Request

bash
curl -N -X POST https://api.sevennadi.si/assistants/setup/sessions/e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9/messages \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"content": "Set up a payment reminder agent for Example Bank, calling between 10:00 and 18:00."}'

Response 200 OK with Content-Type: text/event-stream

Each event has an event: line with its name and a data: line with a JSON object whose type is the same name.

text
event: session
data: {"type": "session", "session_id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9", "provider": "anthropic_api", "label": "Claude API"}

event: text
data: {"type": "text", "delta": "I'll check your account"}

event: text_end
data: {"type": "text_end"}

event: tool
data: {"type": "tool", "name": "get_account", "summary": "", "ok": true}

event: plan
data: {"type": "plan", "plan": {"id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "status": "pending", "operations": []}}

event: done
data: {"type": "done", "status": "awaiting_approval", "usage": {"tool_calls": 4}}
EventWhenData
sessionFirst event of every stream.session_id, provider, label.
textThe assistant is writing.delta: the next piece of text. Append the deltas.
text_endThe current piece of assistant text is complete.None.
toolThe assistant used one of its tools (reading your account, validating, proposing a plan).name, summary, ok, and error when it failed.
planThe assistant proposed a plan. Any earlier pending plan of the session becomes superseded.plan: the full plan object, as in Get a session.
operationOnly after an approval: one operation of the plan ran.See Approve or reject a plan.
plan_statusOnly after a decision: the plan's new status.plan_id, status.
errorThe run failed.message, and sometimes hint.
doneLast event.status: the session's status now (idle or awaiting_approval), and usage.

If the connection drops, the run continues on the server. Read the result with Get a session.

Errors

These are returned as ordinary JSON errors before the stream starts.

StatusMessage
400content is required
400content is limited to 16000 characters
404Session not found
409The assistant is still working on this session
429The setup assistant takes at most 20 messages an hour. Try again later.
503The setup assistant is not available. followed by the operator hint

Approve or reject a plan

POST /assistants/setup/sessions/{session_id}/plan/{plan_id}

Decides a pending plan. Rejecting changes nothing on the account. Approving runs the plan's operations in order with your token, then lets the assistant check the result and report. The response is a stream of server-sent events in both cases.

Auth: API key or session token. Role: member and up. Each operation is an ordinary API request made with your token, so an operation your role may not perform fails with that endpoint's 403.

ParameterInTypeRequiredDescription
session_idpathstring (UUID)yesThe session's id.
plan_idpathstring (UUID)yesThe plan's id.
decisionbodystringyesapprove or reject.
notebodystringnoUp to 1000 characters, stored with the decision. On a rejection the assistant sees it with your next message.
editsbodyarraynoWith approve: changes to the plan. Each entry is {"op_id": "op2", "body": {...}} to replace an operation's body, or {"op_id": "op3", "remove": true} to drop it.
confirm_flaggedbodyarray of stringswhen flaggedWith approve: the id of every operation that has flags.

Request

bash
curl -N -X POST https://api.sevennadi.si/assistants/setup/sessions/e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9/plan/7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -H "Content-Type: application/json" \
  -d '{"decision": "approve"}'

Response 200 OK with Content-Type: text/event-stream

After an approval:

text
event: session
data: {"type": "session", "session_id": "e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9", "provider": "anthropic_api", "label": "Claude API"}

event: operation
data: {"type": "operation", "plan_id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "description": "Create the payment reminder agent", "op_id": "op1", "method": "POST", "path": "/v2/agent", "status": "ok", "ok": true, "status_code": 201, "response": {"agent_id": "3c9d2f8e-1a2b-4c3d-8e4f-5a6b7c8d9e0f"}, "error": null, "links": [{"label": "Open agent", "to": "/agents/3c9d2f8e-1a2b-4c3d-8e4f-5a6b7c8d9e0f"}]}

event: plan_status
data: {"type": "plan_status", "plan_id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "status": "executed"}

event: text
data: {"type": "text", "delta": "The agent is created."}

event: done
data: {"type": "done", "status": "idle", "usage": {"tool_calls": 2}}

An operation event has op_id, status (ok, failed or skipped), ok, status_code, a shortened response with secrets masked, error, and links (dashboard paths for what was created). The first operation that fails stops the plan: the rest are reported as skipped, and the plan's status becomes failed. Operations that already succeeded are not undone. Every operation that was sent is recorded in an audit trail with who approved it.

After a rejection the stream has only two events:

text
event: plan_status
data: {"type": "plan_status", "plan_id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "status": "rejected", "plan": {"id": "7a6b5c4d-3e2f-4a1b-9c8d-7e6f5a4b3c2d", "status": "rejected"}}

event: done
data: {"type": "done", "status": "idle"}

Errors

These are returned as ordinary JSON errors before the stream starts.

StatusMessage
400decision must be approve or reject
400edits: each edit needs the op_id of an operation in this plan
400edits: edit of op2: give a new body or remove: true
400edits: Every operation was removed; reject the plan instead
400confirm_flagged must be a list of operation ids
400op2 (Delete the old agent) is flagged destructive: confirm it explicitly (confirm_flagged) to approve
404Session not found
404Plan not found
409This plan was already executed (or approved, rejected, superseded, failed)
409The assistant is still working on this session
503The setup assistant is not available. followed by the operator hint

Warning: An approved plan makes real changes with your token. Read every operation, and confirm flagged ones only when you mean it.

Agent builder

The agent builder works on a setup session: documents in, a structured draft of one graph agent that you edit, rounds of suggestions you accept one by one, and a plan that creates exactly the draft. Only POST /assistants/setup/sessions/{session_id}/builder/assist runs the model; every other call is immediate. See the Setup assistant guide for the flow.

Auth: API key or session token. Role: viewer and up for reading, member and up for changes.

Attach a document

POST /assistants/setup/sessions/{session_id}/documents

Multipart form with one file: PDF, DOCX, TXT, MD or CSV (judged by its content). Limits: 5 documents per session, 10 MB, 50 pages (text files count parts of about 3,000 characters), 200,000 characters of text kept; all operator-configured. The text is masked at once: card, Aadhaar and account numbers, CVV, OTP, PIN, PAN, other long numbers, phone numbers and e-mail addresses become tags. Names and street addresses are not masked. Only the masked text is ever sent to the assistant.

bash
curl -X POST https://api.sevennadi.si/assistants/setup/sessions/e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9/documents \
  -H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef" \
  -F "file=@collections-sop.txt"

Response 201 Created

json
{"id": "5d1f0e2a-7b3c-4d9e-8f1a-2b3c4d5e6f70", "file_name": "collections-sop.txt", "kind": "txt", "size_bytes": 1184, "pages": 1, "chars": 1102, "masked": {"CARD": 1, "OTP": 1, "PHONE": 1, "EMAIL": 1}, "truncated": false, "created_at": "2026-10-15T09:30:00Z"}

Errors: 400 for another file type, an empty or text-less file (a scanned PDF), a password-protected PDF, or a file over a limit.

List documents

GET /assistants/setup/sessions/{session_id}/documents answers {"documents": [...], "limits": {"max_documents", "max_bytes", "max_pages", "max_chars", "kinds"}}.

Get a document

GET /assistants/setup/sessions/{session_id}/documents/{document_id} answers the document with text: [{"page": 1, "text": "<masked text>"}], exactly what the assistant reads.

Remove a document

DELETE /assistants/setup/sessions/{session_id}/documents/{document_id} answers {"message": "success", "state": "deleted"}; the stored file is deleted.

Get the builder

GET /assistants/setup/sessions/{session_id}/builder

FieldMeaning
version, draftThe current draft and its version (0 and null before a draft is started)
issues, countsProblems with the draft, {"severity": "error"|"warning", "code", "message", "path"}, e.g. steps/greet/transitions/2. Errors block creating the agent
documents, limitsThe attached documents
template_suggestionsby_rules (keyword overlap with your documents) and by_assistant (template_id, fit, reason, evidence with document, page and quote)
suggestionsThe open round: round, base_version, items (id, title, reason, changes, diff with before/after, source, by: rules|assistant, status: open|accepted|rejected|conflict|noted)
rejectedTitles you rejected; the assistant does not offer them again
testsThe last test run on the draft
versionsEvery version: version, source (template, blank, edit, assistant_fill, suggestions, restore), note, errors, warnings
planThe last plan made from the draft
usageTokens per round and session totals with a cost estimate (also in GET /assistants/setup/sessions/{session_id})
privacyWhat is masked and what is sent to the model

Start the draft

POST /assistants/setup/sessions/{session_id}/builder/start

{"template_id": "card-payment-reminder", "values": {"company_name": "Example Bank", "handover_number": "+919800000001"}} starts from a template; every form value is optional here and checked like the form (400 with errors). {"company": "...", "agent_name": "..."} without a template starts a blank three-step draft. Answers the builder.

Save the draft

PUT /assistants/setup/sessions/{session_id}/builder/draft

{"draft": {...}, "base_version": 3, "note": "..."} saves a new version and answers the builder with the new issues. 409 when base_version is not the current version. The draft format: steps (speak, message, router) with transitions (intent with extracted parameters, rule, always, key), safety (transitions from every step), tools (http, transfer, end_call), extraction, compliance, knowledge (text or document), tests.

Ask the assistant

POST /assistants/setup/sessions/{session_id}/builder/assist

{"task": "templates" | "fill" | "improve", "note": "..."}: suggest templates from the documents, fill the draft from them (saved as a new version), or propose a round of suggestions. Answers a text/event-stream like a message (session, text, tool, builder, error, done); done carries usage.round and session_usage. Counts as one assistant message for the hourly limit and billing. 409 without the documents or draft the task needs, 503 without a backend.

Decide suggestions

POST /assistants/setup/sessions/{session_id}/builder/suggestions

{"round": 1, "accept": ["r1s1", "r1s3"], "reject": ["r1s2"]} applies the accepted suggestions in order as one new version and answers the builder with decision: {"applied": [...], "conflicts": [...]}. 409 when the round is not the open one.

Restore a version

POST /assistants/setup/sessions/{session_id}/builder/versions/{version}/restore adds that version's draft as the newest version.

Test the draft

POST /assistants/setup/sessions/{session_id}/builder/tests runs the draft's scenarios and the safety probe with keyword routing (no model, no tools) and answers the builder with tests: results (test_id, name, passed, failures, path, final_node), safety, unreached_steps.

Create the plan

POST /assistants/setup/sessions/{session_id}/builder/plan answers {"plan": {...}, "version": 4}: knowledge files, the graph agent and its extraction fields, exactly as in the draft. 409 while the draft has errors. Approve it with POST /assistants/setup/sessions/{session_id}/plan/{plan_id}; edits to it are refused (edit the draft instead), and no assistant run follows the execution.

Add a knowledge file

POST /assistants/setup/sessions/{session_id}/knowledge

{"title": "Fees", "text": "..."} or {"title": "SOP", "document_id": "..."} (the document's masked text) creates a knowledge file and answers 201 with rag_id, vector_id, file_name, source_type: "text", status: "processing". This is the operation a builder plan runs; attach the file to an agent by its vector_id.