Reference

HTTP API channel

Integrate external apps with Cradle through a local REST API — sync, async, webhook, and scoped authentication.

The HTTP API channel exposes Cradle as a local server for mobile apps, web frontends, CLI tools, cron jobs, and automation platforms. It uses the same triage → RAG → agent → operator flow as Telegram and the widget, so every feature behaves identically across channels.

Default port: 31416. Widget uses 31415 by default.

Authentication

All endpoints under /api/v1/* except /api/v1/health require a key:

Authorization: Bearer <api-key>

or

X-Api-Key: <api-key>

Keys are scoped. See Authentication and scopes for the scope grammar and project-switching rules.

Scopes per endpoint

EndpointMethodScope
/api/v1/healthGET(none)
/api/v1/messagesPOSTmessages:write
/api/v1/messages/:chatIdGETmessages:read
/api/v1/admin/agentsGET / POSTagents:read / agents:write
/api/v1/admin/agents/:id/executePOSTagents:execute
/api/v1/admin/kbGETkb:read
/api/v1/admin/modelsGETmodels:read
/api/v1/admin/models/:catalogId/pullGETmodels:write
/api/v1/admin/ticketsGETtickets:read
/api/v1/admin/keysGET / POSTadmin:*
/api/v1/projects*admin:*

Project header

Admin keys can switch projects per request:

curl -H "x-api-key: ck_live_…" \
     -H "x-cradle-project: support" \
     http://127.0.0.1:31416/api/v1/admin/agents

Scoped keys must use the project they are bound to, or the server returns 403.

POST /api/v1/messages

Send a message into Cradle.

{
  "text": "What is the warranty policy?",
  "chatId": "client-42",
  "userId": "user-123",
  "meta": { "anything": "you-want" },
  "mode": "sync",
  "webhookUrl": "https://your-app.example.com/cradle-webhook",
  "timeoutMs": 60000
}
FieldTypeRequiredDescription
textstringyesMessage text, 1–50 000 characters
chatIdstringnoConversation id; generated as UUID if omitted. Reuse for threading.
userIdstringnoExternal user id, stored in meta.
metaobjectnoArbitrary data saved to tickets.channel_meta.
modeenumnosync (default), async, webhook
webhookUrlstringnoCallback URL. Forces webhook mode.
timeoutMsnumbernoMax wait in ms for sync/webhook. Default from settings, max 120 000.

sync mode

Long-poll until the agent replies or timeout. Response (200):

{
  "ok": true,
  "mode": "sync",
  "chatId": "client-42",
  "ticketId": "550e8400-e29b-41d4-a716-446655440000",
  "replies": [
    { "type": "message", "text": "Warranty is 24 months...", "markdown": false },
    { "type": "attachment", "filename": "warranty.xlsx", "mime": "...", "base64": "..." }
  ]
}

replies is an array. Markdown tables may be returned as XLSX attachments.

async mode

Server immediately returns 202. Replies accumulate in a buffer and are drained via GET /api/v1/messages/:chatId.

{
  "ok": true,
  "mode": "async",
  "chatId": "client-42",
  "ticketId": "550e8400-...",
  "drainUrl": "/api/v1/messages/client-42"
}

webhook mode

Server returns 202 and later POSTs to webhookUrl with an HMAC-SHA256 signature:

X-Cradle-Signature: sha256=<hex>

The secret defaults to the API key if webhookSecret is not configured in the channel settings.

GET /api/v1/messages/:chatId

Drain accumulated replies for a chat.

ParamTypeDescription
:chatIdstringSame id used in POST
waitnumber0 returns immediately; >0 long-polls up to 60 000 ms

Response:

{
  "ok": true,
  "chatId": "client-42",
  "replies": [ { "type": "message", "text": "..." } ]
}

An empty replies array is not an error.

Rate limits

Default: 120 requests / minute / (IP + key).

Enabling the channel

In the desktop app: Integrations → HTTP API:

  1. Generate an API key (at least 16 characters for legacy migration, or use a scoped admin:* key from the CLI).
  2. Choose bindHost:
    • 127.0.0.1 — local processes only.
    • 0.0.0.0 — LAN access (open the firewall only to trusted hosts).
  3. Save and start.

On a headless server the API channel is enabled by default after cradle server init.