Skip to content

Limits & concurrency

Each API key has a cap on how many sessions can be active at once. This protects the rendering pipeline (and your bill) from unbounded growth, and is the main limit you’ll design around.

Responses from session endpoints include two headers so you can self-monitor without guessing:

x-twai-concurrent-sessions: 2
x-twai-max-concurrent-sessions: 3

The cap is per key and set on your account; 3 is the default for a new key. Read the value from the header rather than hard-coding it.

Check these proactively, for example before offering a new conversation to a user, rather than waiting to be throttled.

Once you’re at your cap, POST /v1/sessions returns 429 Too Many Requests with a Retry-After header (in seconds) and the standard error envelope:

{
"error": {
"type": "rate_limit",
"code": "concurrency_cap",
"message": "You have reached your concurrent session limit (3).",
"request_id": "req_9a2c7e1f3b5d"
}
}

There are two, and they mean different things:

error.codeMeaningWhat to do
concurrency_capYou are at your key’s limit.End a session you no longer need, or wait.
platform_busyThe platform as a whole is at capacity. You may be well under your own cap.Back off and retry; it will clear.

Both carry Retry-After: 10.

Handle either by waiting at least Retry-After seconds before retrying, or — for concurrency_cap — by first ending a session you no longer need:

async function createSessionWithBackoff(body) {
const res = await fetch('https://api.2wai.ai/v1/sessions', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.TWAI_SECRET_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
if (res.status === 429) {
const retryAfter = Number(res.headers.get('retry-after') ?? '5');
await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
return createSessionWithBackoff(body);
}
return res.json();
}

The most common cause of hitting the cap isn’t traffic, it’s sessions that were never ended. See the session hygiene checklist: end sessions when a conversation is over (DELETE /v1/sessions/{id}), and consider waiting_state for pauses shorter than a full teardown.

If your default concurrency cap is genuinely too low for your traffic, contact your 2wai account contact. This is a per-account configuration, not something you can change over the API.

  • Sessions for the full lifecycle, including when to end a session versus park it.
  • Errors for the general error envelope.