V1
API v1•Conventions

Errors & Pagination

Standard error response formatting, HTTP status codes, and cursor-based pagination conventions across API v1.

Error Envelope

Every error response returns a JSON object with a human-readable message string and, on v1 resource endpoints, a machine-readable code (NOT_FOUND, VALIDATION_ERROR, CONFLICT, FORBIDDEN):

Error Response
{
"message": "Invalid status: BOGUS. Allowed: NOT_SENT, SENDING, SENT, DELIVERED, FAILED, EXPIRED",
"code": "VALIDATION_ERROR"
}

For definitions of allowed message statuses and lifecycle transitions, see the Message Statuses guide.

HTTP Status Codes

StatusCodeMeaning
400 Bad Request—Missing required request fields, unsupported phone number provider, or invalid sendBefore timestamp.
401 Unauthorized—Missing, malformed, or expired Bearer JWT token.
402 Payment Required—Insufficient active tokens in your billing organization.
403 ForbiddenFORBIDDENAttempting to use a template restricted to another app or modify a PUBLIC template.
404 Not FoundNOT_FOUNDResource does not exist or belongs to another organization/application.
409 ConflictCONFLICTAttempting to modify an already APPROVED template slug.
422 Unprocessable EntityVALIDATION_ERRORTemplate parameter validation failure, unapproved template, invalid filter/date query param, or non-HTTPS webhook URL.
429 Too Many Requests—Per-number OTP cooldown (60s) or sliding 15-minute cap (5 codes) exceeded.
500 Internal Server Error—Unexpected server or upstream queue failure. Safe to retry with an Idempotency-Key.

Common Error Messages

  • "Insufficient tokens" (402) — Top up your organization's balance or check GET /api/v1/balance.
  • "Template '...' is not approved (current status: PENDING)" (422) — Wait for template review or use an already approved template.
  • "Message does not match any approved template" (422) — When sending raw message text, ensure it matches an approved template's pattern and parameter bounds.
  • "Approved templates cannot be modified directly. Please register a new version or slug." (409) — Create a new slug (e.g. otp_login_v2) when changing an approved template.

Cursor Pagination Convention

All list endpoints (GET /messages, GET /batches, GET /batches/:id/messages, GET /ledger, GET /webhooks/:id/deliveries) use deterministic cursor pagination ordered by createdAt desc, id desc:

  • limit: Number of items per page (default 25, min 1, max 100).
  • cursor: Opaque ID of the last item from the previous page (pagination.nextCursor).
  • from / to: Optional ISO 8601 UTC date or datetime filters (from is inclusive, to is exclusive).
Paginated Response Envelope
// Response envelope
{
"data": [ /* ...items... */ ],
"pagination": {
"limit": 25,
"nextCursor": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"hasMore": true
}
}