Contents

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.

ScopeMayMay not
readLook: agents, sources, conversations, analyticsAsk questions, change anything
chatAsk an agent questionsRead conversations or settings, change anything
manageEverything: 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.

CodeStatusMeaning
invalid_request400The body or a parameter is wrong. details names the fields.
unsafe_url400The address to crawl is not on the public internet.
unauthorized401The key is missing, malformed or revoked.
credits_exhausted402The workspace is out of credits for the month.
model_not_allowed402The plan does not include that model.
agent_limit_reached402The plan has no room for another agent.
agent_paused402The agent is beyond what the plan covers.
storage_limit_reached402This would take the agent past its storage allowance.
api_not_in_plan402The plan does not include the API and MCP.
clients_not_in_plan402The plan does not include clients. They come with Agency and up.
forbidden403The key's scope does not allow this.
high_risk_use_case403Recruitment, credit scoring and healthcare are refused as a use case.
not_found404Nothing with that id is visible to this key.
key_limit_reached409The workspace holds its maximum number of keys.
already_corrected409That answer has a correction already.
agent_busy409The agent is still learning something. Retrain once its sources are ready.
file_too_large413The file or image at that address is larger than may be fetched.
unsupported_file_type415The file or image at that address is not of a kind that is taken.
fetch_failed422The address did not give us the file. The message says what came back.
asked_with_file422That answer was to a question with a file, which a Q&A pair cannot carry.
rate_limited429Too many requests. Wait for Retry-After seconds.
internal_error500Our 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:

HeaderMeaning
x-ratelimit-limitRequests allowed per minute
x-ratelimit-remainingRequests left in this minute
x-ratelimit-resetSeconds until the minute ends
Retry-AfterOn 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.