Threll.ai
Reference

Limits & Errors

Rate limits, webhook delivery guarantees, and the complete error catalog across the REST API and MCP server.

What's here

  • Rate limits — gateway throttling and how to back off.
  • Webhook delivery — timeouts, retries, and delivery guarantees.
  • Errors — HTTP statuses, structured 400 types, and MCP errors.
Next: Rate limits
Limits

Rate limits

The API is throttled at the gateway:

LimitValue
Sustained rate1,000 requests/second
Burst100 requests

Requests over the limit are rejected with 429 Too Many Requests. Honor it with exponential backoff and jitter; spread bulk work (like scheduling a large batch of calls) rather than firing it in one burst — scheduled calls exist for exactly that.

Example — backoff on 429

Backoff on 429
async function threllWithRetry(path, options, attempt = 0) {
  const res = await fetch(BASE + path, withAuth(options));
  if (res.status === 429 && attempt < 5) {
    const wait = Math.min(2 ** attempt * 500, 8000) + Math.random() * 250;
    await new Promise(r => setTimeout(r, wait));
    return threllWithRetry(path, options, attempt + 1);
  }
  return res;
}
import random, time

def threll_with_retry(path, attempt=0, **kwargs):
    res = session.request(url=BASE + path, **kwargs)
    if res.status_code == 429 and attempt < 5:
        wait = min(2 ** attempt * 0.5, 8.0) + random.random() * 0.25
        time.sleep(wait)
        return threll_with_retry(path, attempt + 1, **kwargs)
    return res
Limits

Webhook delivery guarantees

Async webhook events are delivered with at-least-once semantics:

Response timeout30 seconds
Each delivery attempt waits up to 30 seconds for your response. Any 2xx counts as delivered; everything else counts as a failure.
Automatic retriesup to 20 attempts
Failed deliveries are retried with backoff for up to 24 hours after the event. After that, the attempt is marked Failed, where it can be retried manually.
Duplicates possible
Retries mean your endpoint can see an event more than once. Deduplicate on X-Threll-Event-Id.
Ordering not guaranteed
Events are dispatched independently; a retried transcript turn can arrive after a later one. Re-order with turnIndex and ts.

Response bodies you return are recorded (truncated to 10 KB) and shown with each attempt for debugging. See the webhooks reference for routing and attempt statuses.

Errors

REST API — HTTP statuses

StatusMeaning
400Validation or configuration error — structured body with a type (below).
401Missing or invalid x-api-key.
404Resource not found, or not visible to your account.
429Rate limit exceeded — back off and retry.
5xxTransient server error — safe to retry idempotent (GET) requests.

Structured 400 error types

Returned when creating phone calls. The body carries statusCode, type, localizedKey, and human-readable details:

TypeFix
TELEPHONY_INTEGRATION_NOT_SETUPSet up Twilio or SIP telephony on the account.
TELEPHONY_INTEGRATION_NOT_ADDED_TO_WORKERAssign the telephony integration to the worker.
TELEPHONY_TRANSPORT_NOT_SUPPORTEDThe call resolved to an unsupported transport; check the worker's integration assignment.
TELEPHONY_THRELL_PROVIDER_UNAVAILABLEVoice provider unavailable — transient, retry later.
CALL_SCRIPT_NOT_CONFIGUREDConfigure a call script for the worker, or pass one on the request.
Errors

MCP server errors

Protocol-level failures use JSON-RPC error codes. Tool-level failures are returned inside a successful response, as a result with an error payload. Authentication failures return 401 with OAuth discovery metadata so clients can re-authorize.

JSON-RPC error
{
  "jsonrpc": "2.0",
  "id": 7,
  "error": { "code": -32602, "message": "Unknown tool: list_wrokers" }
}
Tool-level error (REST /tools/call)
{
  "success": false,
  "error": {
    "code": "INTEGRATION_ERROR",
    "message": "Worker 2b7d9a4c-6e3f-48a1-9c5d-8e0b4f2a1c8d not found in this account"
  }
}