ChatAI Docs
API

API stability

Semver and deprecation policy for the stable /api/v1 REST surface.

ChatAI v1.0 freezes the public HTTP API under /api/v1. The OpenAPI document at GET /api/v1/openapi.json is the contract of record.

Stable surface

AreaRoutesAuth
ChatPOST /api/v1/chatBearer key or keyless widget/playground
VoicePOST /api/v1/voice/sessions, POST /api/v1/voice/sessions/{sessionId}/end, POST /api/v1/voice/sessions/{sessionId}/heartbeat, POST /api/v1/voice/sessions/{sessionId}/gateBearer key (voice scope) or keyless widget/playground (same SecurityPolicy as chat); heartbeat and gate: session controlToken only
Owner REST/api/v1/assistants, documents, conversations, analyticsBearer sk_live_…
WidgetGET …/config, POST /api/v1/feedback, POST /api/v1/widget/signKeyless (domain allowlist + rate limits)

Voice recording is additive: POST /api/v1/voice/sessions accepts an optional recordingConsent and returns recording. When a session would be recorded and consent is required (always for widget/playground, and for API keys when the assistant requires it), a request without recordingConsent: true is rejected with 400. Recording playback is dashboard-only.

Voice minutes are additive. POST /api/v1/voice/sessions can return 402 (reason: "voice_minutes_exhausted") when the account's Voice minutes for the period are used up, and 429 with reason: "voice_concurrency_limit" when too many Voice sessions are active (a plain 429 without reason is still the request rate limit). POST /api/v1/voice/sessions/{sessionId}/end may return endReason: usage_limit when ChatAI closed the call at the end of the account's allowance, superseded when a newer widget session from the same visitor replaced it, otherwise null. Widget (keyless, public) callers never receive usage reasons: mint refusals are 403 with reason: "voice_unavailable", and a usage-limit end is reported as endReason: "voice_unavailable". POST /api/v1/chat accepts an optional voiceUnavailable: true, which the widget sends after such an end so the assistant can answer "why did the voice end?" neutrally; it carries no reason and is not stored. After ChatAI ends a session, the end endpoint still answers for a short time with the final result. The dashboard usage summary (GET /api/v1/account/usage/summary, dashboard session only, not in the OpenAPI spec) includes a voice object with seconds used, limit, reserved and Playground seconds.

Since 1.2.0 every Voice client must declare the playback_gate capability: ChatAI's backend, not the voice model, decides which assistant speech is heard. The client streams decisions from POST /api/v1/voice/sessions/{sessionId}/gate (NDJSON, { token } body) and keeps assistant audio and captions muted unless the gate is open. A mint without playback_gate is refused with 403 and reason: "client_update_required" (since 1.3.0; 1.2.0 answered reason: "voice_unavailable"). The widget and the dashboard Playground declare capabilities: ["heartbeat", "playback_gate"] (exported by @nightzeros/chatai-widget-core as VOICE_CLIENT_CAPABILITIES).

Voice call supervision is additive. A mint request may also declare heartbeat; the response then includes a session-scoped controlToken and heartbeatIntervalMs, and the client posts { token } to POST /api/v1/voice/sessions/{sessionId}/heartbeat. The heartbeat answers healthy, degraded (ChatAI is reconnecting to the provider; heartbeat every nextHeartbeatMs), ended or lost; 421 means the request reached a different server than the one running the call. Only clients that declare the capability are ended when heartbeats stop (after 45 s). endReason gains idle, max_duration, heartbeat_lost and control_lost; widget callers see heartbeat_lost and control_lost as disconnected. The browser's data channel cannot send control events to the provider session; if the provider does not confirm this restriction, the mint fails with 502 and reason: "voice_unavailable".

Dashboard-only routes under /api/assistants/* (uploads, evals, sources, Voice recording playback) are not part of the v1 contract. Integrations should use /api/v1/* only.

Semver rules (API)

We follow Semantic Versioning for product releases. For the HTTP API:

ReleaseAllowed changes on /api/v1
Patch (1.x.y)Bug fixes, documentation, additive optional response fields
Minor (1.x.0)Additive endpoints, optional request fields, new enum values
Major (2.0.0)Breaking request/response shapes, removed routes, auth changes

Breaking changes ship only under a new prefix (e.g. /api/v2) while /api/v1 remains available for at least one major cycle with a published sunset date.

Deprecation process

  1. Mark the field or route deprecated in OpenAPI and docs (minimum 90 days notice).
  2. Emit a Deprecation response header on affected routes when feasible.
  3. Remove only in the next major product release.

Contract tests

The monorepo stores a frozen fingerprint of all documented operations in @nightzeros/chatai-sdk (openapi.fingerprint.json). CI fails if routes are added, removed, or renamed without updating the fingerprint intentionally.

Regenerate after an approved API change:

pnpm --filter @nightzeros/chatai-sdk openapi:fingerprint