Errors
Standard error format and common error cases returned by the API.
Error schema
All error responses follow the same structure.
| Field | Type | Description |
|---|---|---|
error | string | Short error class identifier (ApiError) |
message | string | Human-readable explanation |
status | integer | HTTP status code |
code | string | Machine-readable error code for the specific failure (e.g. inbound_only_no_prior_inbound). Present whenever the response represents a known, programmatically actionable error case. Always switch on code, not on message. |
Some endpoints attach extra context fields alongside code (e.g. limit,
current, allocation_id, external_id). Those are documented per-error
below.
Examples
400 Bad Request
{ "error": "ApiError", "message": "Invalid request parameters.", "status": 400 }attachment_first_message_not_allowed
Returned when the first message in a brand-new conversation contains only attachments and no text. Apple silently drops attachment-only first messages because the chat doesn't yet exist on the device. Send a text message first, then send the attachment.
{
"error": "ApiError",
"message": "Cannot send an attachment as the first message to a new conversation. Apple requires the first message to contain text. Please send a text message first, then send your attachment.",
"status": 400,
"code": "attachment_first_message_not_allowed"
}401 Unauthorized
{ "error": "ApiError", "message": "Invalid or missing API key.", "status": 401 }403 Forbidden
{ "error": "ApiError", "message": "Action not allowed for this API key.", "status": 403 }inbound_only_no_prior_inbound
Returned when the sender is an Inbound plan number and the recipient — a contact for 1:1 chats, or the group itself for group chats — hasn't messaged that number first. Inbound numbers are reply-only: they can answer any contact (or any group) that has messaged them at least once, but they can't initiate new conversations.
{
"error": "ApiError",
"message": "Inbound-only plan: outbound is restricted to contacts who messaged this number first.",
"status": 403,
"code": "inbound_only_no_prior_inbound",
"allocation_id": "alloc_...",
"external_id": "+15555550199"
}Fix: send the first message from a Dedicated or Shared number, then your Inbound number can reply once the contact messages back.
404 Not Found
{ "error": "ApiError", "message": "Resource not found.", "status": 404 }409 Conflict
{ "error": "ApiError", "message": "Conflict with current state.", "status": 409 }429 Too Many Requests
outbound_limit_reached
Returned when the organization (or per-number sender) has reached its 24-hour new-contact limit. The limit and current usage are echoed back so clients can show "X / Y" progress without a second round-trip.
{
"error": "ApiError",
"message": "Outbound contact limit reached. Your organization has reached 35 new contacts in the last 24 hours, which meets the configured limit of 35. Please wait or increase your limit in Settings.",
"status": 429,
"code": "outbound_limit_reached",
"limit": 35,
"current": 35,
"mode": "total"
}Per-number mode adds allocation_id and sender_number so you can tell
which line tripped.
new_conversation_limit_reached
Returned on shared plans only when the organization has reached its plan-defined daily new-conversation cap (15 for Commercial, 20 for Enterprise). Existing conversations continue to send normally.
{
"error": "ApiError",
"message": "New conversation daily limit reached for your plan",
"status": 429,
"code": "new_conversation_limit_reached",
"plan_id": "shared_com",
"cap": 15,
"current": 15
}503 Service Unavailable
{ "error": "ApiError", "message": "No active number available.", "status": 503 }