Talk to your agent programmatically.
The same support agent your visitors talk to on your site, called from your own backend. It answers from your product knowledge over one REST call: JSON by default, Server-Sent Events when you want it token by token, tenant-isolated by key. The guided actions stay in the widget, where the agent can see the page. Included on Pro and Scale, or as the REST API + database connections add-on on Starter and Growth.
One bearer token. Per-agent scope.
API keys are created in the dashboard under the API keys tab on each agent. The clear text is shown once on creation - we only persist a hash, so a leaked key can be revoked but never recovered.
el_sk_ secret keys
Server-side keys with the el_sk_ prefix and 64 hex chars. Use them from your backend - never ship them to a browser. Each key is scoped to one agent or one account, never globally.
Granular scopes
Each key carries an explicit list of scopes (chat:read, chat:write, docs:read, docs:write). Calls that exceed the granted scopes fail with 403 insufficient_scope - safer than per-endpoint allowlists.
Tenant-isolated
Every request resolves to one account_id derived from the bearer token. Tool calls, retrieval, and quota all run against that account - cross-tenant access is impossible by construction.
One-time secret
POST /chatbots/:id/api-keys returns the cleartext exactly once. After that we only have the SHA-256 hash. Revoke a leaked key from the dashboard - the old hash is invalidated immediately.
Authorization: Bearer el_sk_<64 hex chars>
Content-Type: application/jsonWhat each scope unlocks.
Available scopes
chat:read- List the agents this key can see. Read-only over the chatbots resource.chat:write- Send chat turns. Counts against the account's monthly chat quota.docs:read- Read the document corpus for one agent - titles, source type, and ingest status.docs:write- Reserved for document ingestion endpoints (write paths land as the surface grows).
The v1 surface, today.
Stable URL paths under /api/v1/. JSON request and response. SSE opt-in via the Accept header on chat. More endpoints land as the dashboard grows - existing routes never change shape without a major version bump. That promise is why the resource is still spelled chatbots here: we renamed the product, not your integration.
GET/api/v1/chatbots
List the agents this key can see. An agent-scoped key sees one; an account-scoped key sees all.
Scopechat:read
curl https://app.elenn.ai/api/v1/chatbots \
-H "Authorization: Bearer el_sk_..."POST/api/v1/chat
Send a message to an agent. Returns JSON by default; opt into SSE streaming with the Accept header.
Scopechat:write
curl https://app.elenn.ai/api/v1/chat \
-H "Authorization: Bearer el_sk_..." \
-H "Content-Type: application/json" \
-d '{
"chatbot_id": "00000000-0000-0000-0000-000000000000",
"message": "How do I reset my password?"
}'GET/api/v1/chatbots/:id/documents
List the documents indexed for one agent, including chunk count and ingest status.
Scopedocs:read
curl https://app.elenn.ai/api/v1/chatbots/<id>/documents \
-H "Authorization: Bearer el_sk_..."Per-key fixed window.
The default chat limit is 600 requests per hour per API key, applied independently from the per-IP and per-tenant buckets used by the embed widget. Keys on higher-tier plans get a larger allowance - your dashboard shows the current limit and remaining capacity. Exceeding the bucket returns HTTP 429 with the unix-ms reset_at when the window rolls over.
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
{
"error": "rate_limited",
"reset_at": 1716040800000
}One predictable shape.
Every error response is JSON with a stable, lowercase error code that you can switch on in client code. Some errors include extra context - the rate-limit body carries reset_at, the quota body carries used, limit, and plan, and the validation body carries details from Zod.
auth_requiredNo Authorization header on a protected route.
auth_invalidBearer token missing, malformed, or revoked.
insufficient_scopeKey is valid but missing one or more required scopes. The required list is returned in required.
chatbot_outside_key_scopeAn agent-scoped key tried to talk to a different agent.
not_foundAgent or document does not exist in the key's account.
chatbot_inactiveThe agent exists but is_active is false.
invalid_inputZod validation failed. The details field contains a field-by-field error map.
plan_quota_exceededMonthly chat quota for the tenant's plan is used up. The body carries used, limit, and plan.
rate_limitedPer-key fixed-window limit exceeded. reset_at is the unix-ms timestamp when the next window opens.
internal_errorUnexpected server error. The body carries request_id - include it when contacting support.
Send a chat. Stream the response.
The SSE mode emits one sources event before the first token, one token event per chunk, and one terminal done event with the message and conversation ids. On error a single error event closes the stream.
curl -N https://app.elenn.ai/api/v1/chat \
-H "Authorization: Bearer el_sk_..." \
-H "Accept: text/event-stream" \
-H "Content-Type: application/json" \
-d '{
"chatbot_id": "00000000-0000-0000-0000-000000000000",
"message": "How do I reset my password?"
}'
# Server emits:
# event: sources data: {"type":"sources","sources":[…]}
# event: token data: {"type":"token","value":"To "}
# event: token data: {"type":"token","value":"reset "}
# …
# event: done data: {"type":"done","message_id":"…","conversation_id":"…"}HTTP/1.1 200 OK
Content-Type: application/json
{
"conversation_id": "f5b7…",
"message_id": "9c2a…",
"content": "To reset your password, open Settings → Security…",
"sources": [
{ "document_id": "…", "title": "Account settings", "chunk_index": 4 }
]
}What the REST API shares with the rest of Elennai.
Guarantees
- Same RAG pipeline - hybrid retrieval, source attribution, and tool calling, identical to the dashboard and embed widget
- Same multi-tenant isolation - every request resolves to one account_id from the verified bearer token
- Same monthly chat quota as the backoffice - API turns count toward your plan, no separate metered tier
- Same SSE event names as
/chat/streamin the backoffice - sources, token, done, error - Same audit log - key creation, revocation, and usage land in
audit_log_entrieswith 365-day retention - Versioned URL prefix -
/api/v1/is stable; breaking changes ship under a new prefix, never in place
Ready to ship?
Create an account, configure an agent, generate an API key from its API keys tab, and you're three minutes from your first chat turn over REST.