For AI agents: a documentation index is available at the root level at /llms.txt and /llms-full.txt. Append /llms.txt to any URL for a page-level index, or .md for the markdown version of any page.
HomeGet API key
DocumentationIntegrationsAPI Reference
DocumentationIntegrationsAPI Reference
  • Get Started
    • Welcome
  • Guides
    • Agents
    • Phone Numbers
    • Conversations
    • Calls
    • Webhooks
    • Agent Webhooks
    • Usage & Billing
  • Reference
    • Pagination
    • Error Handling
    • Messaging Rate Limits
    • Testing
    • Best Practices
    • Code Examples
    • FAQ
  • SDKs
    • TypeScript / JavaScript
    • Python
LogoLogo
HomeGet API key
On this page
  • Error response format
  • HTTP status codes
  • Error codes
  • VALIDATION_ERROR
  • VALIDATION_ERROR_NUMBER_LIMIT
  • INSUFFICIENT_BALANCE
  • RATE_LIMIT_EXCEEDED
  • PHONE_NUMBER_NOT_FOUND
  • CARRIER_ERROR
  • Handling errors
  • Check response status
  • Handle rate limits
  • Retry transient errors
Reference

Error Handling

Was this page helpful?
Previous

Messaging Rate Limits

Next
Built with

The AgentPhone API uses standard HTTP status codes and returns detailed error information in a consistent JSON format.

Error response format

All errors follow this structure:

1{
2 "error": {
3 "message": "Human-readable error message",
4 "code": "ERROR_CODE",
5 "type": "error_type",
6 "details": []
7 }
8}
FieldDescription
messageHuman-readable description of the error
codeMachine-readable error code (see below)
typeError category (validation_error, rate_limit_error, etc.)
detailsOptional array of field-level validation errors

HTTP status codes

CodeMeaningWhen it occurs
200OKSuccessful GET or POST request
201CreatedSuccessful POST /v1/contacts request (resource created)
400Bad RequestInvalid request parameters or validation error
401UnauthorizedMissing or invalid API key
404Not FoundResource doesn’t exist or you don’t have access
422Unprocessable EntityValidation error (invalid data format)
429Too Many RequestsRate limit exceeded (check Retry-After header)
500Internal Server ErrorServer error (retry with exponential backoff)
502Bad GatewayCarrier service error (retry later)
503Service UnavailableThe server is temporarily unable to handle the request. Retry with exponential backoff.
504Gateway TimeoutThe server did not receive a timely response from an upstream service. Retry with exponential backoff.

Error codes

VALIDATION_ERROR

Request validation failed. Check the details field for specific field errors.

1{
2 "error": {
3 "message": "Validation error",
4 "code": "VALIDATION_ERROR",
5 "type": "validation_error",
6 "details": [
7 {
8 "field": "country",
9 "message": "Country must be a 2-letter ISO code",
10 "type": "value_error"
11 }
12 ]
13 }
14}

VALIDATION_ERROR_NUMBER_LIMIT

Phone number limit reached. Self-serve accounts can provision up to 10 numbers. Contact us to increase your limit.

INSUFFICIENT_BALANCE

Your balance is too low to complete this action. Add funds from the Billing page or enable auto-recharge. Provisioning a number requires at least $3.00.

RATE_LIMIT_EXCEEDED

Rate limit exceeded. Check the Retry-After header for when to retry.

1{
2 "error": {
3 "message": "Rate limit exceeded. Limit: 5 requests per 3600s",
4 "code": "RATE_LIMIT_EXCEEDED",
5 "type": "rate_limit_error"
6 }
7}

PHONE_NUMBER_NOT_FOUND

The requested phone number doesn’t exist or you don’t have access to it.

CARRIER_ERROR

Error from carrier service. Usually a temporary issue — retry with exponential backoff.

Previously returned as TWILIO_ERROR. The deprecated code still works but will be removed in a future version.

Handling errors

Check response status

1import requests
2
3response = requests.post(url, headers=headers, json=data)
4if not response.ok:
5 error = response.json()
6 print(f"API Error: {error['error']['message']}")
7 raise Exception(error['error']['message'])
8data = response.json()
1const response = await fetch(url, options);
2if (!response.ok) {
3 const error = await response.json();
4 console.error('API Error:', error.error.message);
5 throw new Error(error.error.message);
6}
7const data = await response.json();

Handle rate limits

1import time, requests
2
3def request_with_retry(url, headers, json=None, max_retries=3):
4 for i in range(max_retries):
5 response = requests.post(url, headers=headers, json=json)
6 if response.status_code == 429:
7 retry_after = int(response.headers.get('Retry-After', 60))
8 time.sleep(retry_after)
9 continue
10 response.raise_for_status()
11 return response.json()
12 raise Exception('Max retries exceeded')
1async function requestWithRetry(url, options, maxRetries = 3) {
2 for (let i = 0; i < maxRetries; i++) {
3 const response = await fetch(url, options);
4 if (response.status === 429) {
5 const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
6 await new Promise(r => setTimeout(r, retryAfter * 1000));
7 continue;
8 }
9 if (!response.ok) throw new Error(`Request failed: ${response.status}`);
10 return response.json();
11 }
12 throw new Error('Max retries exceeded');
13}

Retry transient errors

For 429, 500, 502, 503, and 504 errors, implement exponential backoff:

1from requests.adapters import HTTPAdapter
2from urllib3.util.retry import Retry
3
4session = requests.Session()
5retry_strategy = Retry(
6 total=3,
7 backoff_factor=1,
8 status_forcelist=[429, 500, 502, 503, 504]
9)
10adapter = HTTPAdapter(max_retries=retry_strategy)
11session.mount("https://", adapter)

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).