Error Handling
The AgentPhone API uses standard HTTP status codes and returns detailed error information as JSON.
Error response format
Most API errors follow this structure:
Some responses use a plain {"detail": "..."} body with no error code instead. This includes authentication errors (401/403), endpoint throttling (429 with a Retry-After header), the outbound-call concurrency cap (429, no Retry-After), insufficient balance (402), and number-related 409s. Robust error handling should check for both shapes.
HTTP status codes
Error codes
VALIDATION_ERROR
Request validation failed. Check the details field for specific field errors.
Number limit reached
Self-serve accounts can provision up to 10 numbers. POST /v1/numbers returns HTTP 409 with a plain {"detail": "..."} body when you hit the cap. Contact us to increase your limit.
Insufficient balance
Your balance is too low to complete a paid action. Returned as HTTP 402 with a plain {"detail": "..."} body; the message describes the balance requirement (for example, the minimum needed to provision a number and your current balance). Add funds from the Billing page or enable auto-recharge. Provisioning a number requires at least $3.00.
Rate limiting (429)
429 responses come in three flavors:
- Endpoint throttles return a plain
{"detail": "Too many requests. Please try again in N seconds."}body with aRetry-Afterheader. Wait that long, then retry. - Call concurrency caps on
POST /v1/callsreturn a plain{"detail": "Concurrent outbound call limit reached (N). Please wait for an active call to end."}body with noRetry-Afterheader. This clears as your active calls end, so wait briefly and retry. - Messaging limits return the error envelope with a specific code and no
Retry-Afterheader.RATE_LIMITEDis transient; the cap codes (CONVERSATION_STREAK_LIMIT,CONVERSATION_AWAITING_REPLY,CONVERSATION_INACTIVE,OUTBOUND_LIMIT_REACHED,NEW_CONVERSATION_LIMIT_REACHED, described below) clear only when the recipient replies or a daily window resets, never on retry.
RATE_LIMITED
Sending too fast. Returned with HTTP 429. This one is transient: slow down and retry shortly. No Retry-After header is included.
PHONE_NUMBER_NOT_FOUND
The requested phone number doesn’t exist or you don’t have access to it.
CONVERSATION_STREAK_LIMIT
You’ve sent too many messages in a row to one contact without a reply. Returned with HTTP 429.
Retrying will not clear this. The count only resets when the contact replies, and the limit applies to that one conversation, so your other threads keep sending. See Messaging Rate Limits for details.
OUTBOUND_LIMIT_REACHED
You’ve reached the daily cap for messaging contacts who have never messaged your line. Returned with HTTP 429.
Contacts who have messaged you before are not affected, so replies and re-engagement still go through. The cap resets daily and can be raised on request.
NEW_CONVERSATION_LIMIT_REACHED
You’ve reached the daily cap for starting new conversations. Returned with HTTP 429. Replies to existing conversations still go through, and the cap resets daily.
CONVERSATION_AWAITING_REPLY
Up to 3 messages can be sent to a brand-new recipient before they respond. Returned with HTTP 429. Retrying does not clear it; it unlocks when the recipient replies.
CONVERSATION_INACTIVE
The conversation has been inactive for over 14 days and its single re-engagement message was already sent. Returned with HTTP 429. It unlocks when the recipient replies.
INBOUND_ONLY
This line can’t send the first message to a new recipient. Returned with HTTP 422. Ask the recipient to message you first, or contact support to enable first-touch sends on the line.
WHATSAPP_NOT_ENABLED
WhatsApp has been switched off for this account. Returned with HTTP 403. WhatsApp is on by default for everyone, so this only appears if it was disabled manually. Email [email protected] to have it restored.
WhatsApp send errors
WhatsApp sends are rejected by Meta rather than by a carrier, and the reason comes back in the error message. The ones worth handling in code:
Template sends outside the window are the single most common WhatsApp failure. Check capabilities.whatsappWindowExpiresAt on the conversation before a free-form send rather than discovering it from a 422.
Provider errors
SMS_PROVIDER_ERROR, MESSAGE_PROVIDER_ERROR, and TELEPHONY_PROVIDER_ERROR indicate a failure at an upstream messaging or telephony provider, usually returned with HTTP 502. These are typically temporary, but the operation may have executed before the failure. See the retry guidance below before resending.
Handling errors
Check response status
Handle both body shapes: the error envelope and the plain {"detail": "..."} form.
Handle rate limits
Only retry 429s that retrying can actually clear: endpoint throttles (which carry a Retry-After header), call concurrency caps (which clear as active calls end), and the transient RATE_LIMITED code. The messaging-cap codes don’t reset on retry, so surface them instead.
Retry transient errors
For 429, 500, 502, 503, and 504 errors on idempotent requests (GETs, and retries of the same update), implement exponential backoff:
The API does not currently support idempotency keys. A 5xx on a send (POST /v1/messages, POST /v1/calls) can occur after the operation has already executed, so blindly retrying can double-send or double-bill. Before retrying a failed send, confirm whether it went through (for example, list recent messages in the conversation).
If you’re using the official SDKs, retry logic is built in. The TypeScript SDK automatically retries on 408, 429, and 5xx errors with exponential backoff (default: 2 retries).

