API overview
Keys, scopes, the shape of every response, errors, limits and paging. Everything that holds for the whole REST API.
Whatever you can do in the dashboard, you can do over the API, under the same rules. A plan limit that stops you in the dashboard stops a key in the same way, and every change a key makes is written to the audit log together with the key that made it.
Base address
https://chatterlab.ai/api/v1
The exact address for your workspace is under Settings, in the block API keys. If you serve from your own domain, it is your hostname, and on your hostname a key only ever reaches your own workspace.
Keys
Create a key under Settings, API keys. You choose a name, a scope and, if you like, one agent to tie it to.
Keys, and with them the API and the MCP server, come with Studio and up. On Free and Starter no key can be made. A key made on a higher plan stays, but is refused with api_not_in_plan while the workspace is on a plan below Studio. It works again as soon as you move back to Studio or higher.
- A key looks like
cl_followed by 48 characters. It is shown once. We store only a fingerprint of it, so a lost key cannot be recovered, only replaced. - Send it with every request:
curl https://chatterlab.ai/api/v1/agents \
-H "Authorization: Bearer cl_your_key"
- A workspace holds up to 25 keys. Revoke takes effect at once.
- Keys belong on a server. Never put one in a web page or an app a user can open. For a chat on a website, use the widget, which needs no key.
Scopes
A key can do one of three things. They are not steps on a ladder: each answers a different question. In the dashboard they are called Read, Chat and Manage.
| Scope | May | May not |
|---|---|---|
read | Look: agents, sources, conversations, analytics | Ask questions, change anything |
chat | Ask an agent questions | Read conversations or settings, change anything |
manage | Everything: read, ask, create, change, delete |
So a key in your website's backend that only asks questions cannot read other visitors' conversations if it leaks, and a key for a reporting tool cannot spend your credits. Give every integration the narrowest scope that works.
A key tied to one agent
Tie a key to an agent and it sees that agent only. Every other agent answers not_found, as if it did not exist. Such a key is also not told about your workspace: not your plan, your credits or your other keys. It is the key to hand to a client's developers.
Responses
Every response is JSON with one of three shapes.
{ "data": { "id": "ag_...", "name": "Support" } }
{ "data": [ ... ], "pagination": { "nextCursor": "..." } }
{ "error": { "code": "invalid_request", "message": "...", "details": [ { "field": "name", "message": "..." } ] } }
Times are ISO 8601 in UTC. Identifiers are strings with a prefix that says what they are: ag_ an agent, src_ a source, conv_ a conversation, msg_ a message. Every response has an x-request-id header. Quote it if you write to us about a request.
Request bodies are strict
Send JSON with Content-Type: application/json. A field we do not know is an error, not something we ignore: a misspelt temprature gets you a 400 that names the field, instead of a setting that silently never changed.
Errors
The code is stable and meant for your program. The message is meant for a person and may be reworded.
| Code | Status | Meaning |
|---|---|---|
invalid_request | 400 | The body or a parameter is wrong. details names the fields. |
unsafe_url | 400 | The address to crawl is not on the public internet. |
unauthorized | 401 | The key is missing, malformed or revoked. |
credits_exhausted | 402 | The workspace is out of credits for the month. |
model_not_allowed | 402 | The plan does not include that model. |
agent_limit_reached | 402 | The plan has no room for another agent. |
agent_paused | 402 | The agent is beyond what the plan covers. |
storage_limit_reached | 402 | This would take the agent past its storage allowance. |
api_not_in_plan | 402 | The plan does not include the API and MCP. |
clients_not_in_plan | 402 | The plan does not include clients. They come with Agency and up. |
forbidden | 403 | The key's scope does not allow this. |
high_risk_use_case | 403 | Recruitment, credit scoring and healthcare are refused as a use case. |
not_found | 404 | Nothing with that id is visible to this key. |
key_limit_reached | 409 | The workspace holds its maximum number of keys. |
already_corrected | 409 | That answer has a correction already. |
agent_busy | 409 | The agent is still learning something. Retrain once its sources are ready. |
file_too_large | 413 | The file or image at that address is larger than may be fetched. |
unsupported_file_type | 415 | The file or image at that address is not of a kind that is taken. |
fetch_failed | 422 | The address did not give us the file. The message says what came back. |
asked_with_file | 422 | That answer was to a question with a file, which a Q&A pair cannot carry. |
rate_limited | 429 | Too many requests. Wait for Retry-After seconds. |
internal_error | 500 | Our fault. Retrying later is reasonable. |
A 402 always means "a plan matter": retrying will not help, a change to the plan or the credits will.
Rate limit
120 requests a minute per key. Every response tells you where you stand:
| Header | Meaning |
|---|---|
x-ratelimit-limit | Requests allowed per minute |
x-ratelimit-remaining | Requests left in this minute |
x-ratelimit-reset | Seconds until the minute ends |
Retry-After | On a 429: seconds to wait |
The limit is shared between the API and MCP when both use the same key.
Paging
Sources and conversations come 50 at a time, newest first. Ask for up to 100 with ?limit=. When there is more, pagination.nextCursor holds a value to pass as ?cursor= for the next page. When it is null, you have everything. A cursor is opaque: pass it back unchanged. Agents come all at once, oldest first, in the same envelope with nextCursor always null.
Stability
Within /api/v1 we add, and do not take away: new fields, new endpoints and new error codes can appear, and existing ones keep their name and meaning. Write your client to ignore fields it does not know.
Next: the API reference.