Error Handling

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 request
201CreatedSuccessful POST 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 GatewayTwilio service error (retry later)

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 for your plan. Contact us to add more phone lines.

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.

TWILIO_ERROR

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

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