External Chat API
Drive MCintelligentplus chat turns from your own apps with scoped API keys
External Chat API
The External Chat API lets an external application — your own product, a
workflow tool, a support widget — send chat turns into MCintelligentplus and
stream the agent's answer back. It is mounted at /api/v1/ext and accepts only
chat-scoped personal access tokens bound to an API client; cookie sessions
and plain JWTs are rejected. When the API client requires it, every request
also carries the client's client key in the X-MCip-Client-Key header:
the chat key says which user is asking, the client key says which external
system is calling.
Endpoints
| Method | Path | Purpose |
|---|---|---|
GET | /api/v1/ext/me | Validate the key and list the usable workspaces |
POST | /api/v1/ext/chat | One chat turn — stream=false returns the aggregated JSON answer, stream=true returns SSE |
GET | /api/v1/ext/conversations/{id}/messages | Transcript of a conversation the key created |
DELETE | /api/v1/ext/conversations/{id} | Delete a conversation |
GET | /api/v1/ext/openapi.json · /api/v1/ext/docs | Public OpenAPI document and docs page for this router only |
Error responses are a flat {errorCode, message, request_id} body; auth
failures are API_KEY_MISSING / API_KEY_INVALID / API_KEY_EXPIRED /
API_KEY_SCOPE and the client-key ones CLIENT_KEY_MISSING /
CLIENT_KEY_INVALID, and busy conversations answer CONVERSATION_BUSY (with
retry_after_ms) or CONVERSATION_AWAITING_APPROVAL (with continue_url).
API clients and keys
An API client is the security envelope: it always belongs to an
organisation, can be disabled, and can pin an IP allowlist (ip_allowlist,
CIDR entries) that rejects requests from anywhere else. A key inherits the
client's rules, and the key can only reach workspaces of the client's
organisation where its user holds the chat permission; the "via client" badge
on a chat shows which client produced a turn.
Create and manage these in:
- Org portal → Settings → API clients
(
/org/<slug>/settings/api-clients) — the organisation's clients; system admins manage any organisation's clients through its page. - User Settings → Apps & API access → API key (
/user-settings/apps-and-api-access/api-key) — personal keys, including chat-scoped keys for the External Chat API.
Every client row in Org → Settings → API clients opens a Keys panel listing that client's chat keys — prefix, label, owner, expiry, and last use — with a show expired toggle. Keys can be revoked there singly or in bulk; a revocation takes effect immediately (the external app is cut off on its next call) and the key's owner is notified.
Client keys (ss_cli_…)
A client key is the credential of the external system, separate from the
per-user chat keys: all of a client's users share one client key, and it is
sent as the X-MCip-Client-Key header next to each user's Authorization: Bearer ss_pat_…. Creating a client generates its first client key; the create
dialog shows it once (client_key in the create response, only its hash is
stored). Each client's Client key panel shows the key's state — Active,
Grace until …, Revoked, Expired — with Create key / Rotate key
and per-key revoke:
- Rotate issues a new key and keeps the current one working for a 24-hour grace so the external system can switch with no downtime. Rotating again inside the grace window ends the older grace key immediately; at most two keys are valid at once.
- Revoke stops a key on its next request and cannot be undone.
- The Require client key switch (on by default for new clients, off for
clients created before this feature) makes every request without a valid
client key answer
401 CLIENT_KEY_MISSING. Even with the switch off, a present wrong key is rejected with401 CLIENT_KEY_INVALID, so a bad key never silently works. The switch can only be turned on while an active key exists (the UI otherwise asks you to create or rotate one first).
Caps and rate limits
| Limit | Env var | Default |
|---|---|---|
| Requests/minute per key | EXT_API_KEY_RATE_PER_MINUTE | 30 |
| Concurrent turns per key | EXT_API_KEY_MAX_CONCURRENT | 3 |
| Chat keys per user per client | PAT_MAX_CHAT_KEYS_PER_CLIENT | 5 (0 = no cap) |
| Require chat-scoped keys for new PATs | PAT_REQUIRE_CHAT_SCOPE | FALSE |
Additional hard caps live in code: a POST /ext/chat request body is capped at
64 KB (rejected at the ASGI layer with 413 REQUEST_TOO_LARGE before parsing)
and a single message at 32,000 characters. Per-client rate limits are set on
each API client. When PAT_REQUIRE_CHAT_SCOPE=TRUE, creating a full-access PAT
returns 400 PAT_FULL_SCOPE_DISABLED (existing full keys keep working).
Where in the UI
- Admin → API Clients and Org → Settings → API clients — client lifecycle, organisation, IP allowlist, per-client limits, each client's Keys panel (list, show-expired toggle, single and bulk revoke), and the client's Client key panel (issue, rotate with 24-hour grace, revoke, and the Require client key switch).
- User Settings → Apps & API access → API key — create/revoke keys and see their scope.
- Org → Settings → Security (
/org/<slug>/settings/security) — every full-access key held by org members; member-held keys can be revoked (revoking also disables the key in the owner's other orgs and workspaces), owner-held keys are read-only. - Chat sidebar — the "via client" badge marks turns from external clients.
Related PRs
- #1140 — E1: keys, API clients, trusted IP
- #1141 — E2:
/api/v1/extendpoints - #1142 — E3: API keys UI, API clients admin page, via-client badge
- #1160 — E4: load test, security fixes, guide
- #1164 — follow-ups: DB pool, chat-key cap,
org_policyorigin - #1195 / #1196 — per-client chat keys and the org security page for full keys
- #1207 — client keys (
ss_cli_) for external-system authentication - Design tracker: #1120