Error Code Reference
Every Orbit API error response includes a machine-readable code, human-readable message, HTTP status, and contextual details. Use this reference to diagnose and resolve errors programmatically.
{
"error": {
"code": "INVALID_PHONE_NUMBER",
"message": "The 'to' field must be a valid E.164 phone number",
"status": 422,
"details": {
"field": "to",
"value": "+1234",
"expected": "E.164 format e.g. +14155552671"
}
},
"meta": {
"request_id": "req_abc123",
"timestamp": "2026-03-08T00:00:00Z",
"docs_url": "https://orbit-docs.devotel.io/errors/INVALID_PHONE_NUMBER"
}
}
Authentication & Authorization
| Code | HTTP | Description | Resolution |
|---|
UNAUTHORIZED | 401 | Missing or invalid authentication | Include a valid X-API-Key header or Authorization: Bearer token |
INVALID_API_KEY | 401 | API key is malformed, revoked, or does not exist | Generate a new key in Settings > API Keys |
EXPIRED_TOKEN | 401 | JWT bearer token has expired | Re-authenticate to obtain a fresh token |
INSUFFICIENT_PERMISSIONS | 403 | Authenticated identity lacks the required RBAC role | Check the user’s role (owner, admin, developer, viewer, billing) |
FORBIDDEN | 403 | Access to the resource is denied | Verify the resource belongs to your organization |
Validation
| Code | HTTP | Description | Resolution |
|---|
VALIDATION_ERROR | 400/422 | One or more fields failed validation | Check details.field and details.expected for specifics |
INVALID_PHONE_NUMBER | 422 | Phone number not in E.164 format | Format as +[country code][number] (e.g., +14155552671) |
INVALID_EMAIL | 422 | Email address is syntactically invalid | Verify the email format |
INVALID_TEMPLATE | 422 | Message template is malformed or has missing parameters | Check template variables match the content |
MISSING_REQUIRED_FIELD | 422 | A required field was omitted | See details.field for the missing field name |
INVALID_CURSOR | 400 | Pagination cursor is malformed or expired | Start pagination from the beginning without a cursor |
INVALID_WEBHOOK_URL | 422 | Webhook URL is unreachable or returned an error | Ensure the URL is publicly accessible and returns 2xx |
Resource
| Code | HTTP | Description | Resolution |
|---|
NOT_FOUND | 404 | Resource does not exist | Verify the ID or path |
ALREADY_EXISTS | 409 | Duplicate unique key (e.g., phone number in contacts) | Use a different identifier or update the existing resource |
CONFLICT | 409 | Operation conflicts with current resource state | Check the resource status before retrying |
TENANT_NOT_FOUND | 404 | Organization not found for this API key | Verify your API key is associated with an active organization |
Rate Limiting
| Code | HTTP | Description | Resolution |
|---|
RATE_LIMIT_EXCEEDED | 429 | Too many requests in the current window | Wait details.retry_after seconds, then retry. See Rate Limits |
QUOTA_EXCEEDED | 429 | Plan-level quota reached | Upgrade your plan or wait for the next billing cycle |
BURST_LIMIT_EXCEEDED | 429 | Too many requests per second | Spread requests more evenly across time |
Messaging
| Code | HTTP | Description | Resolution |
|---|
MESSAGE_SEND_FAILED | 500 | Downstream provider rejected the message | Retry with POST /v1/messages/{id}/retry |
CHANNEL_UNAVAILABLE | 503 | Channel is temporarily offline or not configured | Verify channel configuration in dashboard; retry later |
TEMPLATE_NOT_APPROVED | 422 | WhatsApp/RCS template not approved by carrier | Submit for approval in Messages > Templates |
INVALID_RECIPIENT | 422 | Recipient is unreachable or blocked by carrier | Verify the number is active and not on a block list |
RECIPIENT_OPTED_OUT | 422 | Recipient opted out of communications | Remove from send list; do not retry |
MESSAGE_TOO_LONG | 422 | Message body exceeds maximum length | Reduce content or split into multiple messages |
MEDIA_TOO_LARGE | 422 | Attached media exceeds size limit | Compress or resize media (max 16 MB for WhatsApp) |
SENDER_NOT_CONFIGURED | 422 | No sender number configured for the channel | Purchase and configure a number for this channel |
Voice
| Code | HTTP | Description | Resolution |
|---|
CALL_FAILED | 500 | Outbound call could not be placed | Check the destination number and SIP trunk config |
SIP_ERROR | 502 | SIP-level error from the trunk | See details.sip_code for the SIP response code |
VOICE_GATEWAY_ERROR | 502 | Voice gateway internal error | Retry; contact support if persistent |
CALL_NOT_FOUND | 404 | Call ID does not exist or has expired | Verify the call ID |
CALL_ALREADY_ENDED | 409 | Attempted to modify a completed call | No action needed |
AI Agents
| Code | HTTP | Description | Resolution |
|---|
AGENT_ERROR | 500 | Agent failed during execution | Check agent logs in the dashboard |
LLM_PROVIDER_ERROR | 502 | LLM provider returned an error | Transient — retry with backoff |
GUARDRAIL_VIOLATION | 422 | Output blocked by Portkey guardrail | Review guardrail config in agent settings |
AGENT_NOT_DEPLOYED | 422 | Agent is in draft or paused state | Deploy or resume the agent first |
TOOL_EXECUTION_FAILED | 500 | Agent tool call failed | Check tool endpoint availability |
CONTEXT_TOO_LONG | 422 | Conversation context exceeds model limit | Start a new conversation or reduce context |
Numbers
| Code | HTTP | Description | Resolution |
|---|
NUMBER_NOT_AVAILABLE | 409 | Number was claimed by another customer | Search for a different number |
NUMBER_ALREADY_OWNED | 409 | Number is already on your account | No action needed |
PORT_REQUEST_FAILED | 422 | Number porting request was rejected | Verify carrier info and authorization name |
Billing
| Code | HTTP | Description | Resolution |
|---|
PAYMENT_REQUIRED | 402 | Valid payment method required | Add a card in Settings > Billing |
SUBSCRIPTION_INACTIVE | 403 | Subscription is paused or cancelled | Reactivate in Settings > Billing |
INSUFFICIENT_CREDITS | 402 | Prepaid credit balance too low | Top up credits via API or dashboard |
CHECKOUT_EXPIRED | 410 | Checkout session has expired | Create a new checkout session |
System
| Code | HTTP | Description | Resolution |
|---|
INTERNAL_ERROR | 500 | Unexpected server error | Include request_id when contacting support |
SERVICE_UNAVAILABLE | 503 | Service temporarily down or overloaded | Retry with exponential backoff |
WEBHOOK_DELIVERY_FAILED | 500 | Webhook delivery to your endpoint failed | Check endpoint availability and response time |
MAINTENANCE_MODE | 503 | Scheduled maintenance in progress | Check status.devotel.io |
Handling Errors in Code
Node.js
import { Devotel, DevotelApiError } from '@devotel/sdk'
try {
await devotel.messages.send({ channel: 'sms', to: 'invalid', body: 'Hi' })
} catch (error) {
if (error instanceof DevotelApiError) {
console.error(`[${error.code}] ${error.message}`)
console.error(`Status: ${error.status}`)
console.error(`Request ID: ${error.requestId}`)
}
}
Python
from devotel import Devotel, DevotelApiError
try:
devotel.messages.send(channel="sms", to="invalid", body="Hi")
except DevotelApiError as e:
print(f"[{e.code}] {e.message}")
print(f"Status: {e.status}")
print(f"Request ID: {e.request_id}")
Always include the request_id from the error response meta when contacting Orbit support. This allows us to trace the exact request through our infrastructure.