Errors and rate limits: what to retry, what to surface
HTTP status codes Call2Me returns, rate limit headers, retry-after semantics, and the patterns that make integrations survive carrier hiccups.
Updated May 6, 2026
Most production issues don't come from the happy path — they come from how integrations handle the unhappy ones. This is the reference for what the platform returns and how to react.
Status codes you'll see
| Code | Meaning | What to do |
|---|---|---|
| 200 OK | Success | — |
| 201 Created | Resource created | Read Location header for canonical URL |
| 400 Bad Request | Validation failed | Fix the request; don't retry as-is |
| 401 Unauthorized | Missing or bad auth | Check Bearer token; do NOT retry |
| 402 Payment Required | Wallet too low | Top up, then retry |
| 403 Forbidden | Auth okay, scope insufficient | Mint a key with the right scope |
| 404 Not Found | Resource doesn't exist | Don't retry; check the ID |
| 409 Conflict | Idempotency or state conflict | Inspect; usually no retry |
| 422 Unprocessable | Schema valid but logically wrong | Fix the request |
| 429 Too Many Requests | Rate limited | Back off; respect Retry-After |
| 500 Internal Server Error | Platform side bug | Retry with exponential backoff |
| 502 / 503 / 504 | Upstream issue | Retry with exponential backoff |
Error response shape
Every error has the same body:
{
"error": {
"code": "validation_failed",
"message": "to_number must be in E.164 format",
"field": "to_number",
"request_id": "req_abc123"
}
}
Always log request_id. When you open a support ticket, that's the only
piece of info we need to trace the request through every internal hop.
Rate limits
Limits are per-API-key, sliding window. Each response includes:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1714998000
When you hit zero:
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Retry-After is in seconds. Wait that long, then retry. If you're seeing
429 frequently, contact support to discuss raising your limits — for
high-volume customers we tune them per workspace.
Idempotency
For POST requests that create resources (/v1/calls, /v1/agents,
/v1/schedules), pass an Idempotency-Key header:
curl -X POST https://api.call2me.app/v1/calls \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Idempotency-Key: 8c7b3a4d-1e2f-4abc-9def-0123456789ab" \
-H "Content-Type: application/json" \
-d '{...}'
The platform stores the response keyed by your idempotency key for ~24 hours. A retry with the same key returns the cached response — no duplicate call placed, no duplicate agent created.
Use a fresh UUID per logical request; don't reuse keys across genuinely different requests.
Retry strategy that works in production
attempt 1 → fail with 502
wait 1s
attempt 2 → fail with 502
wait 2s
attempt 3 → fail with 502
wait 4s
attempt 4 → succeed
Caps to apply:
- max attempts: 5
- max total wait: 30s
- never retry 4xx (except 408, 429)
- always honor
Retry-Afterif present
Most HTTP client libraries have this built in — use the library, don't reinvent it.
What's next
- Authentication — the 401 and 403 root causes
- Webhooks — retry semantics for events you receive
- Pricing — when 402 is right and what to do about it
Frequently asked
Q.Are 5xx errors safe to retry?
Yes — with exponential backoff. 5xx means the platform side failed; idempotent operations (GET, PUT, DELETE) can be retried as-is. For POST, use the Idempotency-Key header to make retries safe.
Q.How does rate limiting work?
Per-API-key, sliding window. Headers X-RateLimit-Limit and X-RateLimit-Remaining tell you where you stand. When you hit zero, you get 429 with a Retry-After header.
Q.What's an idempotency key?
A client-generated UUID you send with POST requests. The platform deduplicates within a short window — retrying with the same key returns the cached response instead of creating a duplicate.
Q.Why am I getting 402 Payment Required?
Wallet balance is below the minimum to start a call. Top up via dashboard or POST /v1/wallet/topup, then retry.