Platform
ScaiWave ScaiGrid ScaiCore ScaiBot ScaiDrive ScaiKey Models Tools & Services
Solutions
Organisations Developers Internet Service Providers Managed Service Providers AI-in-a-Box
Resources
Support Documentation Blog Downloads
Company
About Research Careers Investment Opportunities Contact
Log in

API reference

All endpoints are mounted at /v1/modules/scaibot/ and authenticate with the standard ScaiGrid bearer token. Responses use ScaiGrid's standard envelope ({ "data": ... } for success, { "error": ... } for failures).

Bots#

GET /bots#

List bots in the caller's tenant.

bash
1
2
curl "$SCAIGRID_HOST/v1/modules/scaibot/bots" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY"

Query parameters: limit (1-100, default 20), cursor, status (active, draft, archived).

POST /bots#

Create a bot.

Field Required Notes
name yes Human-readable name.
slug yes URL-safe, unique within tenant.
model yes Frontend model id (scailabs/poolnoodle-omni, etc.).
display_name no What the bot calls itself; defaults to name.
welcome_message no First message visitor sees.
placeholder_text no Input field placeholder.
primary_color no Hex; defaults to tenant theme.
max_tokens_per_response no Default 500.
max_context_messages no History window. Default 20.
knowledge_enabled no Default false.
knowledge_mode no managed (default if enabled) or linked.
knowledge_collection_id when linked ScaiMatrix collection id.
knowledge_settings no top_k, score_threshold, max_chunks_per_doc, deduplicate.

Returns 201 Created with the new bot.

GET /bots/{bot_id}#

Fetch one bot's full config.

PUT /bots/{bot_id}#

Replace the bot's config. All editable fields above are settable here.

PATCH /bots/{bot_id}/status#

Move the bot between lifecycle states.

json
1
{ "status": "draft" | "active" | "archived" }

DELETE /bots/{bot_id}#

Hard-delete the bot. Conversations are retained (anonymised). Cascades to knowledge, escalation rules, tone.

Embed tokens#

POST /bots/{bot_id}/embed-token#

Mint a short-lived token for the widget.

Field Notes
ttl_seconds 60 – 86400. Default 3600.
visitor_id Optional; appears in analytics and conversation records.
visitor_email Optional.
visitor_name Optional.
metadata Arbitrary JSON; carried through to the conversation.
json
1
2
3
4
5
6
7
8
{
  "data": {
    "token": "sbt_...",
    "expires_at": "2026-04-22T15:00:00Z",
    "bot_id": "bot_abc123",
    "widget_url": "https://.../widget.js"
  }
}

GET /bots/{bot_id}/embed-info#

Public, unauthenticated. Returns the widget URL and basic display config — used by the widget at load time. Does not return a token.

DELETE /bots/{bot_id}/embed-token#

Revoke a token before its TTL expires. Body: { "token": "sbt_..." }.

Chat#

POST /chat#

Send a message in a conversation. Response is a Server-Sent Event stream.

bash
1
2
3
4
5
6
7
8
curl -N -X POST "$SCAIGRID_HOST/v1/modules/scaibot/chat" \
  -H "Authorization: Bearer $SCAIGRID_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "bot_id": "bot_abc123",
    "conversation_id": "cnv_xyz",
    "message": "What are your refund terms?"
  }'

Events:

Event Payload
start { "conversation_id": "...", "message_id": "..." }
token { "delta": "..." }
citation { "marker": "1", "document_id": "...", "snippet": "..." }
escalation { "rule_id": "...", "action_type": "...", "message": "..." }
done { "total_tokens": 123, "latency_ms": 1450 }
error { "code": "...", "message": "..." }

Omit conversation_id to start a new conversation; the start event contains the assigned id.

Query parameter include_system_prompt=true adds a system_prompt event at the start (admin only — requires scaibot:conversations:read).

Tone#

GET /bots/{bot_id}/tone#

Read current tone config.

PUT /bots/{bot_id}/tone#

Set tone. See Tone for fields.

POST /bots/{bot_id}/tone/preview#

Generate one non-streamed response with a proposed tone.

json
1
2
3
4
{
  "tone": { "formality": "formal", "verbosity": "verbose" },
  "sample_message": "What are your refund terms?"
}

Returns { "data": { "response": "...", "tokens": 84 } }.

Escalation#

GET /bots/{bot_id}/escalations#

List rules in priority order.

POST /bots/{bot_id}/escalations#

Create a rule. Body fields:

Field Notes
name Human label.
priority Higher fires first; default 50.
trigger_type keyword, intent, sentiment, confidence, explicit.
trigger_config Type-specific (see Escalation).
action_type email, webhook, slack, scaiqueue.
action_config Type-specific.
message What the bot says when this rule fires.

Returns 201 Created.

PUT /bots/{bot_id}/escalations/{rule_id}#

Replace a rule.

DELETE /bots/{bot_id}/escalations/{rule_id}#

Remove a rule. Returns 204 No Content.

POST /bots/{bot_id}/escalations/reorder#

Bulk-reorder priorities.

json
1
{ "order": ["rule_id_1", "rule_id_2", "rule_id_3"] }

Knowledge#

GET /bots/{bot_id}/documents#

List documents and their indexing status.

POST /bots/{bot_id}/documents#

Upload a document. Multipart form data: file (binary), name (string).

GET /bots/{bot_id}/documents/{doc_id}#

Fetch one document's metadata and status.

PUT /bots/{bot_id}/documents/{doc_id}#

Replace a document's file. Same multipart form as POST. Re-indexes.

DELETE /bots/{bot_id}/documents/{doc_id}#

Remove a document; chunks drop out of retrieval immediately.

Conversations#

GET /conversations#

List conversations.

Query parameters:

Parameter Notes
bot_id Filter to one bot.
visitor_id Filter to one visitor.
status active, closed, escalated.
since ISO 8601 timestamp.
limit, cursor Pagination.

GET /conversations/{conversation_id}#

Full transcript including all turns, citations, retrieved chunks, escalation events.

json
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
  "data": {
    "id": "cnv_xyz",
    "bot_id": "bot_abc123",
    "visitor_id": "usr_42",
    "started_at": "2026-04-22T14:01:00Z",
    "status": "active",
    "messages": [
      {
        "role": "user",
        "content": "What are your refund terms?",
        "created_at": "..."
      },
      {
        "role": "assistant",
        "content": "Refunds are processed within 14 business days [^1].",
        "citations": [{"marker":"1","document_id":"doc_abc","snippet":"...","score":0.84}],
        "tokens": 67,
        "latency_ms": 1240,
        "created_at": "..."
      }
    ],
    "escalations": []
  }
}

PATCH /conversations/{conversation_id}/status#

Manually close a conversation.

json
1
{ "status": "closed" }

Errors#

All endpoints return ScaiGrid's standard error envelope:

json
1
2
3
4
5
6
7
8
{
  "error": {
    "code": "BOT_NOT_FOUND",
    "message": "Bot bot_abc123 not found in tenant ten_xyz",
    "details": { "bot_id": "bot_abc123" }
  },
  "meta": { "request_id": "req_..." }
}

ScaiBot-specific codes:

Code Meaning
BOT_NOT_FOUND Bot id doesn't exist (or you can't see it).
BOT_SLUG_TAKEN Slug already in use within tenant.
BOT_INVALID_MODEL Model id not available to your tenant.
CONVERSATION_NOT_FOUND Conversation id doesn't exist or doesn't belong to this bot.
EMBED_TOKEN_EXPIRED Token expired; mint a fresh one.
EMBED_TOKEN_INVALID Token signature didn't verify.
DOCUMENT_TOO_LARGE Single document exceeded 50 MB.
DOCUMENT_UNSUPPORTED File type not supported.
KNOWLEDGE_COLLECTION_NOT_FOUND Linked-mode collection id missing or no access.
ESCALATION_TRIGGER_INVALID Trigger config didn't validate (e.g. bad regex).
ESCALATION_ACTION_FAILED Action attempted but downstream rejected (e.g. webhook 5xx).
TONE_INVALID Tone field combination not allowed.
Updated 2026-05-18 15:01:26 View source (.md) rev 17