Skip to main content
The messages.dev REST API is a JSON over HTTPS API. Every endpoint is reachable from any language with an HTTP client.

Base URL

https://api.messages.dev/v1
Your base URL is shown in your dashboard.

Authentication

Authenticate every request with a bearer token:
Authorization: Bearer sk_live_...
Create API keys from your dashboard. See Authentication for scopes and line restrictions.

Requests

All request bodies are JSON encoded as UTF-8 with Content-Type: application/json. The API supports CORS for GET, POST, DELETE, and OPTIONS.

Responses

Single resources return the object directly:
{ "id": "msg_01h...", "text": "hello", "created_at": 1712188800000 }
List endpoints return an envelope with cursor pagination fields:
{ "data": [ ... ], "has_more": false, "next_cursor": null }
Errors return a consistent envelope:
{
  "error": { "type": "invalid_request_error", "code": "missing_required_parameter", "message": "..." },
  "request_id": "req_..."
}

Conventions

  • Field names use snake_case.
  • IDs are prefixed by resource type: msg_, cht_, ln_, rxn_, obx_, wh_, ind_, rcp_, file_.
  • Timestamps are Unix milliseconds (UTC).
  • Every response includes a request_id. Include it when reporting issues.

Pagination

List endpoints are cursor-paginated. When has_more is true, pass next_cursor as the cursor query parameter on the next request:
curl "https://api.messages.dev/v1/messages?cursor=eyJp..." \
  -H "Authorization: Bearer sk_live_..."

Asynchronous writes

Write endpoints (POST /messages, /reactions, /typing, /receipts) accept the request and return an outbox record with status queued:
{ "id": "obx_...", "status": "queued", "resource_type": "message" }
The daemon delivers it over iMessage or SMS and reports back. Track delivery by:
  • Webhooks (recommended): subscribe to message.sent, message.failed, etc.
  • Polling: GET /outbox?id=obx_...

Errors

The API maps to standard HTTP status codes (2xx success, 4xx client error, 5xx server error). See Errors for the full taxonomy and error codes.

Rate limits

API keys are rate limited per hour. When exceeded, the API returns 429 with a Retry-After header indicating the seconds to wait. See rate limit errors for details.

DELETE with a request body

DELETE /webhooks takes the resource ID in the request body, not the URL:
curl -X DELETE https://api.messages.dev/v1/webhooks \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "wh_abc123"}'

TypeScript SDK

If you’re using TypeScript, the official SDK wraps this API with a typed client, cursor helpers, and typed errors.