Assistant
An AI sales coach your customers' staff can talk to, inside your product, under your name. It knows how that business's own calling has actually gone, and it will not tell them who builds the platform — including us.
Two credentials, on purpose
Everything else on this API takes your API key. The assistant takes a session token, and the difference is the whole design:
| API key | Session token | |
|---|---|---|
| Looks like | kls_live_… | kls_sess_live_… |
| Lives on | Your server | One person's browser |
| Can do | Everything its permissions allow, for every customer | Send messages to the assistant, for one customer |
| Lasts | Until you rotate it | 60–3600 seconds (900 by default) |
The flow
- Your backend calls
POST /v1/customers/{id}/sessionswith your API key andend_user_ref— your own identifier for the person about to use it. - You hand the returned token to that person's browser. It comes back exactly once.
- Their browser calls
POST /v1/chatwith it. Cross-origin is allowed and no cookie is used, so this works from your own domain with no proxy of your own. - When they are done — or when they leave your company — call
DELETEwith theirend_user_ref.
What it knows, and what it will not say
The assistant is grounded in that one customer's last 30 days of calling: how many calls were requested, how many finished, the connect rate, average length, outcomes and appointments booked. It never sees another business's data, and a figure that was not measured is not stated — a customer with nothing finished yet gets help preparing rather than a fabricated 0%.
It will not:
- name any company that supplies you — no platform, telephony, AI or hosting vendor. Ask it who powers this and it answers that it is your platform.
- claim to be human. Asked directly, it says it is an AI assistant.
- discuss billing, pricing or plans. Those are your commercial terms, so it points the person at you.
- advise anything non-compliant — no fabricated consent, no ignoring a do-not-call request, no pretending a call is not recorded where disclosure is required.
Limits and cost
| Limit | Value | Why |
|---|---|---|
| Message length | 4,000 characters | Longer than any real question. |
| History replayed | 12 turns | You send the thread and keep it; we read the tail. Kleos stores no transcript. |
| Messages per session | 200 | A ceiling, so a token copied out of a browser costs a conversation, not a bill. |
| Cost per message | 0.02 USD | Charged only when an answer is actually produced. A failed message costs nothing. See pricing. |
In test mode the whole flow works and nothing is charged — a test key mints test sessions, and a test session is priced but never billed.
Mint a chat session for one of your customer's staff
POST/v1/customers/{id}/sessions
Your backend calls this; the token it returns goes to that person's browser. NEVER put your API key in a front end — a key is your whole account, every customer and every permission, and a browser is a place you do not control. A session can do exactly one thing: talk to the assistant, for this one customer, until it expires. The token comes back exactly once; we store only a hash of it. Minting again does not revoke earlier sessions — a person legitimately has two tabs open. Use DELETE to revoke.
Permission: chat:write
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
Body
| Field | Type | |
|---|---|---|
end_user_ref * | string | YOUR identifier for the person. Kleos does not want your user table — this is what makes a session revocable and an audit entry attributable. Up to 128 characters. |
display_name | string | How to address them. Up to 120 characters. |
ttl_seconds | integer | How long the session lives: 60 to 3600 seconds. Defaults to 900. Out of range is refused, never clamped. |
Response
{
"object": "chat_session",
"id": "d4f1c2a8-31b7-4f0e-8c95-1a7b2d3e6f04",
"prefix": "kls_sess_test_a7Bq2X",
"end_user_ref": "user-4471",
"display_name": "Marie Lambert",
"expires_at": "2026-08-04T09:27:44.000Z",
"revoked_at": null,
"last_used_at": null,
"messages_sent": 0,
"message_limit": 200,
"created_at": "2026-08-04T09:12:44.000Z",
"token": "kls_sess_test_…",
"expires_in_seconds": 900
}Refusals
| Status | Code | When |
|---|---|---|
| 400 | end_user_ref_required | No `end_user_ref` was sent. |
| 400 | ttl_out_of_range | `ttl_seconds` was outside 60–3600. |
| 404 | customer_not_found | No customer with that id in this mode. |
| 500 | session_not_created | Nothing was created and nothing was charged. Retry safely. |
Ask the assistant a question
POST/v1/chat
The one endpoint authenticated by a SESSION token rather than an API key, because it is the only one a browser is meant to reach: send `Authorization: Bearer kls_sess_…`. The assistant is a sales coach grounded in that customer's own recent calling, and it speaks as YOUR brand — it will not name any supplier, including us. Cross-origin requests are allowed, and no cookie is used. You send the conversation with each turn and keep it; Kleos stores no transcript. Each message costs a flat rate from your balance, and only when an answer is actually produced.
Authentication: an end-user kls_sess_… session token, not an API key.
Body
| Field | Type | |
|---|---|---|
message * | string | What the person asked. Up to 4,000 characters. |
history | string | The conversation so far, as `[{role: 'user'|'assistant', content: '…'}]`. The last 12 turns are used; older ones are ignored so a long thread cannot quietly cost more. |
Response
{
"object": "chat_message",
"reply": "Your connect rate is 41% over 68 finished calls, which is healthy for a cold list…",
"messages_sent": 7,
"message_limit": 200,
"session_expires_at": "2026-08-04T09:27:44.000Z",
"charged_cents": 2
}Refusals
| Status | Code | When |
|---|---|---|
| 400 | message_required | The message was empty. |
| 400 | message_too_long | The message exceeded 4,000 characters. |
| 401 | invalid_session_token | The token is malformed, unknown, or not a session token. |
| 401 | session_expired | The session passed its expiry. Mint another. |
| 401 | session_revoked | The session was revoked. Mint another. |
| 402 | insufficient_balance | Your balance cannot cover the message. Top up. |
| 429 | session_exhausted | The session hit its message ceiling. Mint another. |
| 503 | chat_unavailable | No answer was produced. Nothing was charged. Retry. |
See who has a live session, and how much they have used it
GET/v1/customers/{id}/sessions
Sessions for this customer, newest first, with how many messages each has sent. The token is never returned again — only its prefix, so you can tell two apart in a support conversation.
Permission: customers:read
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
Response
{
"object": "list",
"data": [
{
"object": "chat_session",
"id": "d4f1c2a8-31b7-4f0e-8c95-1a7b2d3e6f04",
"prefix": "kls_sess_test_a7Bq2X",
"end_user_ref": "user-4471",
"display_name": "Marie Lambert",
"expires_at": "2026-08-04T09:27:44.000Z",
"revoked_at": null,
"last_used_at": "2026-08-04T09:19:02.000Z",
"messages_sent": 6,
"message_limit": 200,
"created_at": "2026-08-04T09:12:44.000Z"
}
],
"has_more": false
}Refusals
| Status | Code | When |
|---|---|---|
| 404 | customer_not_found | No customer with that id in this mode. |
End a session, or every session for one person
DELETE/v1/customers/{id}/sessions
Pass `session_id` for one, or `end_user_ref` to end every live session that person holds — which is the form you want when somebody leaves. Revoking takes effect on their next message, not at their next expiry. Revoking something already ended returns `revoked: 0` and is a success, so a retry is safe.
Permission: chat:write
Parameters
| Name | In | Type | |
|---|---|---|---|
id * | path | string | Kleos id or your `external_ref`. |
session_id | query | string | Revoke this one session. |
end_user_ref | query | string | Revoke every live session for this person. |
Response
{
"object": "chat_session_revocation",
"revoked": 2
}Refusals
| Status | Code | When |
|---|---|---|
| 400 | session_selector_required | Neither `session_id` nor `end_user_ref` was given. |
| 404 | customer_not_found | No customer with that id in this mode. |