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.
| Operation | Method and path | Minimum role |
|---|---|---|
| Ask a question | POST /assistants/ask | member |
| List Ask conversations | GET /assistants/ask/sessions | viewer |
| Get setup assistant status | GET /assistants/setup/status | viewer |
| List templates | GET /assistants/setup/templates | viewer |
| Get a template | GET /assistants/setup/templates/{template_id} | viewer |
| Create a brief from a template | POST /assistants/setup/templates/{template_id}/brief | member |
| Create a session | POST /assistants/setup/sessions | member |
| List sessions | GET /assistants/setup/sessions | viewer |
| Get a session | GET /assistants/setup/sessions/{session_id} | viewer |
| Send a message | POST /assistants/setup/sessions/{session_id}/messages | member |
| Approve or reject a plan | POST /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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
messages | body | array | yes | 1 to 40 messages, oldest first. The conversation so far, ending with the question. |
messages[].role | body | string | yes | user or assistant. |
messages[].content | body | string | yes | Up to 4000 characters. |
Request
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
{"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:
{"reply": null, "provider": "none"}The reply text is illustrative; it comes from a language model and can be wrong.
Errors
| Status | Message |
|---|---|
| 400 | messages must be a non-empty list (at most 40) |
| 400 | each message needs role user|assistant and string content |
| 400 | messages are limited to 4000 characters |
| 502 | The 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
curl https://api.sevennadi.si/assistants/ask/sessions \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK
{"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:
provider | Meaning |
|---|---|
claude_code | A local Claude Code installation on the operator's server. |
anthropic_api | The Anthropic API, with the operator's API key. |
fake | A scripted demo that always follows the same steps. For tests; it can only be selected where the operator allows it. |
none | No 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
runningfor 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_assistantledger 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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
backend | query | string | no | fake asks about the scripted demo. It is honoured only where the operator allows it. |
Request
curl https://api.sevennadi.si/assistants/setup/status \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK
{"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
curl https://api.sevennadi.si/assistants/setup/templates \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK (one of several)
{
"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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
template_id | path | string | yes | A template id from the list. |
Request
curl https://api.sevennadi.si/assistants/setup/templates/card-payment-reminder \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK (shortened)
{
"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
| Status | Message |
|---|---|
| 404 | Template 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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
template_id | path | string | yes | A template id. |
values | body | object | yes | One entry per field key. Required fields must be present; unknown keys are refused. |
Request
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)
{
"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.
{
"error": 400,
"message": "Company name is required",
"errors": {"company_name": "is required", "call_start": "is required"}
}| Status | Message |
|---|---|
| 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 |
| 400 | The details are too long for one request; shorten the longer answers |
| 404 | Template 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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
title | body | string | no | Up to 200 characters. If empty, the first message becomes the title. |
template_id | body | string | no | The template this session starts from. |
backend | body | string | no | Only fake is accepted, to request the scripted demo. The server picks the real backend. |
The body may be omitted.
Request
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
{
"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:
{"session_id": null, "provider": "none", "label": "Not available", "available": false, "hint": "..."}Errors
| Status | Message |
|---|---|
| 400 | backend may only be 'fake' (the scripted demo); the server picks the real one |
| 400 | template_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
curl https://api.sevennadi.si/assistants/setup/sessions \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK
{
"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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id | path | string (UUID) | yes | The session's id. |
Request
curl https://api.sevennadi.si/assistants/setup/sessions/e4b2a1c0-9d8e-4f7a-b6c5-d4e3f2a1b0c9 \
-H "Authorization: Bearer vk-0123456789abcdef0123456789abcdef"Response 200 OK (shortened)
{
"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.
| Field | Meaning |
|---|---|
transcript[].type | user, assistant, tool, plan, decision, results or error. |
plans[].status | pending, superseded (a newer plan replaced it), approved, rejected, executed or failed. |
plans[].operations[].id | op1, 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[].flags | Empty, or any of destructive and spends_money. Flagged operations need explicit confirmation. |
plans[].results | After the plan ran: one result per operation. See the operation event below. |
Errors
| Status | Message |
|---|---|
| 404 | Session 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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id | path | string (UUID) | yes | The session's id. |
content | body | string | yes | Your request, or a brief from a template. Up to 16,000 characters. |
Request
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.
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}}| Event | When | Data |
|---|---|---|
session | First event of every stream. | session_id, provider, label. |
text | The assistant is writing. | delta: the next piece of text. Append the deltas. |
text_end | The current piece of assistant text is complete. | None. |
tool | The assistant used one of its tools (reading your account, validating, proposing a plan). | name, summary, ok, and error when it failed. |
plan | The assistant proposed a plan. Any earlier pending plan of the session becomes superseded. | plan: the full plan object, as in Get a session. |
operation | Only after an approval: one operation of the plan ran. | See Approve or reject a plan. |
plan_status | Only after a decision: the plan's new status. | plan_id, status. |
error | The run failed. | message, and sometimes hint. |
done | Last 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.
| Status | Message |
|---|---|
| 400 | content is required |
| 400 | content is limited to 16000 characters |
| 404 | Session not found |
| 409 | The assistant is still working on this session |
| 429 | The setup assistant takes at most 20 messages an hour. Try again later. |
| 503 | The 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.
| Parameter | In | Type | Required | Description |
|---|---|---|---|---|
session_id | path | string (UUID) | yes | The session's id. |
plan_id | path | string (UUID) | yes | The plan's id. |
decision | body | string | yes | approve or reject. |
note | body | string | no | Up to 1000 characters, stored with the decision. On a rejection the assistant sees it with your next message. |
edits | body | array | no | With 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_flagged | body | array of strings | when flagged | With approve: the id of every operation that has flags. |
Request
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:
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:
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.
| Status | Message |
|---|---|
| 400 | decision must be approve or reject |
| 400 | edits: each edit needs the op_id of an operation in this plan |
| 400 | edits: edit of op2: give a new body or remove: true |
| 400 | edits: Every operation was removed; reject the plan instead |
| 400 | confirm_flagged must be a list of operation ids |
| 400 | op2 (Delete the old agent) is flagged destructive: confirm it explicitly (confirm_flagged) to approve |
| 404 | Session not found |
| 404 | Plan not found |
| 409 | This plan was already executed (or approved, rejected, superseded, failed) |
| 409 | The assistant is still working on this session |
| 503 | The 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.
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
{"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
| Field | Meaning |
|---|---|
version, draft | The current draft and its version (0 and null before a draft is started) |
issues, counts | Problems with the draft, {"severity": "error"|"warning", "code", "message", "path"}, e.g. steps/greet/transitions/2. Errors block creating the agent |
documents, limits | The attached documents |
template_suggestions | by_rules (keyword overlap with your documents) and by_assistant (template_id, fit, reason, evidence with document, page and quote) |
suggestions | The open round: round, base_version, items (id, title, reason, changes, diff with before/after, source, by: rules|assistant, status: open|accepted|rejected|conflict|noted) |
rejected | Titles you rejected; the assistant does not offer them again |
tests | The last test run on the draft |
versions | Every version: version, source (template, blank, edit, assistant_fill, suggestions, restore), note, errors, warnings |
plan | The last plan made from the draft |
usage | Tokens per round and session totals with a cost estimate (also in GET /assistants/setup/sessions/{session_id}) |
privacy | What 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.