Skip to main content

Documentation Index

Fetch the complete documentation index at: https://messages.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

The messages.dev REST API is a JSON over HTTPS API. Every endpoint is reachable from any language with an HTTP client. For TypeScript and Node.js, the @messages-dev/sdk package is the recommended integration path. It wraps every endpoint in this reference with a typed client, handles cursor pagination, throws typed errors, and ships a verifyWebhook() helper that gets the HMAC signature scheme right (HMAC(${timestamp}.${body}) with replay protection).
npm install @messages-dev/sdk
import { createClient } from "@messages-dev/sdk";

const client = createClient(); // reads MESSAGES_API_KEY

await client.sendMessage({
  from: "+15551234567",
  to: "+15559876543",
  text: "Hello from Messages.dev!",
});
See the SDK reference for the full surface area. If you’re not on TypeScript — or you just want to know what’s on the wire — the rest of this page documents the underlying REST API directly.

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, /audio-messages, /reactions, /typing, /receipts) accept the request and return an outbox record with status pending:
{ "id": "obx_...", "status": "pending", "request_id": "req_..." }
Messages.dev delivers it over iMessage or SMS and reports back. Track delivery by:
  • Webhooks (recommended): subscribe to message.sent. Outgoing messages share the same shape as inbound ones (is_from_me: true).
  • Polling: GET /outbox?id=obx_... — status transitions through pendingclaimedsent (or failed, with the failure reason in error).

Sending: contact-first

Outside the sandbox, you can only send to a contact (or group chat) after they have messaged your line first. Sending to a cold contact returns 403 contact_has_not_messaged. See Send a message for the full flow.

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"}'