#Rate Limiting
The AiDial API enforces application-level and infrastructure-level rate limits to protect service availability. When a request is rejected by a rate limiter, the API returns a 429 Too Many Requests response.
#Detecting Rate Limits
A 429 HTTP status code indicates you have been rate-limited. Before parsing the response body, check the Content-Type header and retry signals:
- JSON body (
application/json): Parse the response for error details and retry timing - Non-JSON body (
text/plainortext/html): Infrastructure-level rate limit; do not attempt to parse as JSON - Retry timing: Prefer the
Retry-Afterresponse header when present; otherwise use a documented retry field in the JSON body, such asretry_after_seconds
#Current Application and Edge Limits
| Surface | Current limit | Retry signal |
|---|---|---|
| Edge proxy main API router | Traefik average 1,200 requests per 1-minute period with a burst of 300 | No JSON contract guaranteed |
| Partner API key and webhook operations | 5 requests per authenticated identity, target tenant, and operation per 60 seconds for API-key create/rotate and webhook create/rotate-secret/test routes | Retry-After header |
| CSV export | 3 requests per user/tenant pair, and 12 requests per tenant, per 600 seconds | retry_after_seconds body |
| Transcript downloads | 10 requests per user/tenant pair, and 60 requests per tenant, per 300 seconds across TXT and PDF downloads | retry_after_seconds body |
| SCIM security endpoints | 30 configuration updates per authenticated identity, tenant, data environment, and operation per 60 seconds; 120 provisioning events per scoped API-key identity, tenant, and data environment per 60 seconds | Retry-After header |
| Communication email routing | Add email: 10 per user/tenant per 24 hours; resend verification: 3 per user/email/tenant per 1 hour; public token verification: 10 per source IP per 60 seconds | Retry-After header and retry_after_seconds body |
| Account export jobs | 3 create requests per user/tenant/data environment, and 10 per tenant/data environment, per 24 hours | Retry-After header |
| Report schedule sample sends | 5 per actor/tenant per 600 seconds, and 3 per tenant/frequency/recipient-set per 900 seconds | Retry-After header and details.retry_after_seconds body |
| Business-hours project options | 20 requests per authenticated actor per 60 seconds | field_errors.retry_after_seconds body |
| Portal MFA lifecycle mutation | 5 requests per client, user, and action per 60 seconds | Retry-After header and retry_after_seconds body |
| Support portal surfaces | Route-local per-actor/operation limits over 60 seconds: ticket search 30, badge/open-count 60, related-call validation 60, related-call attach/detach 20, recipient add/remove 20, attachment readiness/list/scan-status 60, attachment finalise/download 30, attachment session-start/delete 12 | No retry timing |
| Public demo dial-me | Current configured limits are 3 per phone per hour, 10 per phone per day, and 10 per resolved public source IP per day; active call and runtime capacity blocks also return 429 | No retry timing |
#Response Formats
For public demo dial-me IP limiting, the source IP is resolved through the trusted request-provenance helper before counters are updated. Spoofed forwarded headers from untrusted direct peers are ignored, while malformed trusted proxy chains or chains that resolve only to internal/trusted infrastructure are rejected with 400 before dispatch.
#General HTTPException-Based Routes
Some routes return the general error shape from the global FastAPI exception handler:
HTTP/1.1 429 Too Many Requests
Content-Type: application/json{
"error": "Rate limit exceeded",
"status_code": 429
}These responses do not guarantee retry timing.
When an HTTPException carries a structured detail object, the global handler wraps that object in error. The Support portal surfaces use this form, raising a 429 with a rate_limit_exceeded code and an operation-specific message and no retry timing:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests."
},
"status_code": 429
}#Partner Endpoints
Partner endpoints using the shared rate limiter return the partner error envelope and include a Retry-After response header:
HTTP/1.1 429 Too Many Requests
Retry-After: 3
Content-Type: application/json{
"error": {
"code": "rate_limited",
"message": "Too many requests. Please retry shortly.",
"message_key": "rate_limited",
"status": 429,
"request_id": "9b603a24-4d95-4d0b-a865-20c0f8a2c5de"
}
}SCIM rate limits use the same partner envelope with code set to rate_limited; the message text is SCIM-specific.
#Billing Endpoints
Billing 429 responses use the billing domain error shape. When the billing provider supplies retry timing, AiDial includes a Retry-After response header with the number of seconds to wait:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json{
"code": "billing_provider_rate_limited",
"message": "Billing provider rate limit exceeded."
}#Export and Transcript Download Endpoints
POST /v1/calls/export, GET /v1/calls/{call_id}/transcript-download, and GET /v1/calls/{call_id}/transcript/pdf return export/download error bodies. Their 429 responses include retry_after_seconds in the response body:
{
"error": "rate_limited",
"code": "EXPORT_THROTTLED",
"message": "Export throttled. Please wait and try again.",
"messageKey": "calls.export.messages.throttled",
"retry_after_seconds": 60
}Transcript TXT and PDF downloads share the same download limiter and use DOWNLOAD_THROTTLED:
{
"error": "rate_limited",
"code": "DOWNLOAD_THROTTLED",
"message": "Transcript download throttled. Please wait and try again.",
"messageKey": "calls.transcriptDownload.messages.throttled",
"retry_after_seconds": 9
}Concurrent CSV exports for the same user and tenant return 409 Conflict with EXPORT_IN_PROGRESS, not 429.
#Portal Domain Endpoints
Several portal-facing domain endpoints return a flat domain error shape.
Communication email routing uses code: "rate_limited" and includes both Retry-After and retry_after_seconds:
{
"code": "rate_limited",
"message": "Request rate limit exceeded.",
"retry_after_seconds": 60
}Account export job creation uses code: "export_rate_limited" and includes Retry-After:
{
"code": "export_rate_limited",
"message": "Account export request limit reached for this user."
}Report schedule sample sends include retry timing under details and set Retry-After:
{
"code": "rate_limited",
"message": "Too many requests. Please try again later.",
"details": {
"reason": "actor",
"retry_after_seconds": 600
}
}Business-hours project options use the domain error shape and put retry timing in field_errors:
{
"code": "business_hours_options_rate_limited",
"message": "Request rate limit exceeded.",
"field_errors": {
"retry_after_seconds": "60"
}
}#Portal MFA Lifecycle
PUT /v1/portal-mfa-lifecycle applies a route-local limiter per client, user, and action. Its 429 response uses the domain error shape and includes both Retry-After and retry_after_seconds:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
Content-Type: application/json{
"code": "rate_limited",
"message": "Too many requests. Please wait and try again.",
"retry_after_seconds": 60
}#Infrastructure-Level Rate Limiting
Infrastructure-level rate limiting is enforced by Traefik for the main API router with an average of 1,200 requests per minute and a burst of 300. It may return a 429 response with a non-JSON body (plain text or HTML). Your integration must handle this gracefully:
HTTP/1.1 429 Too Many Requests
Content-Type: text/plain
Rate limit exceeded#Recommended Retry Strategy
Use exponential backoff with jitter:
- Check
Content-Typebefore parsing the 429 body - If
Retry-Afterheader is present: Wait the specified number of seconds - If JSON with documented retry timing: Use
retry_after_seconds,details.retry_after_seconds, orfield_errors.retry_after_secondswhere documented for that endpoint - If non-JSON or no retry timing: Wait a minimum of 60 seconds
- On subsequent retries: Double the wait time (60s, 120s, 240s) up to a maximum of 10 minutes
- Add jitter: Add a random delay of 0-5 seconds to avoid thundering herd effects
#Related Pages
- Error Responses — all error formats and status codes
- Authentication — API key and bearer authentication