Platform
Rate limits and concurrency
Two things are limited: how fast a workspace may send requests, and how many calls it may be on at once. Both answer 429 when reached, and both are safe to retry.
Rate limits
| What | Limit | Counted per |
|---|---|---|
| Requests of any kind | 300 a minute | Workspace, across all its keys |
| Calls started | 20 a minute | Workspace, across all its keys |
| Requests with bad credentials | 30 a minute | Network address |
Past a limit, requests are refused until the minute is up:
{
"error": "Too many requests. Slow down and retry.",
"code": "RATE_LIMITED",
"status": 429,
"retryAfterSeconds": 23
}The Retry-After header carries the same number of seconds. The limits are there to stop a runaway loop, not to meter normal use.
Calls at once
A workspace can be on a set number of calls at the same time. The number comes from its plan and is returned as maxConcurrentCalls by Check a key. Starting one call too many answers:
{
"error": "This workspace can run 5 calls at once and 5 are active. End one or retry shortly.",
"code": "WORKSPACE_CONCURRENCY_LIMIT_REACHED",
"status": 429,
"activeCalls": 5,
"maxConcurrent": 5
}A slot is freed when a call ends. Much more rarely, the platform as a whole is at capacity and answers CONCURRENCY_LIMIT_REACHED; retry shortly.
Handling a 429
Wait, then try again, a few times at most. For a caller who is waiting, tell them the line is busy instead of retrying forever.
async function startCall(body, attempt = 0) {
const response = await fetch('https://goblins-call-api.onrender.com/v1/calls', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.CRACKLE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (response.status === 429 && attempt < 3) {
// Rate limits say how long to wait; a busy line is worth a short pause and another try.
const seconds = Number(response.headers.get('retry-after')) || 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
return startCall(body, attempt + 1);
}
if (!response.ok) throw new Error((await response.json()).error);
return response.json();
}Other limits
| What | Limit |
|---|---|
| Request body | 1 MB |
| Agent instructions | 25,000 characters |
| Text for Speak into a call | 2,000 characters |
| Webhooks attached to one call | 5 |
| Calls per page of List calls | 100 |
| API keys per workspace | 25 |
| Time a tool’s endpoint has to answer | 30 seconds |