> ## 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.

# Overview

> Base URL, authentication, and conventions for the REST API

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

## Recommended: use the TypeScript SDK

For TypeScript and Node.js, the [`@messages-dev/sdk`](/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).

```bash theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
npm install @messages-dev/sdk
```

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
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](/sdk) 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](https://app.messages.dev).

## Authentication

Authenticate every request with a bearer token:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
Authorization: Bearer sk_live_...
```

Create API keys from your [dashboard](https://app.messages.dev/api-keys).
See [Authentication](/concepts/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:

```json theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
{ "id": "msg_01h...", "text": "hello", "created_at": 1712188800000 }
```

List endpoints return an envelope with cursor pagination fields:

```json theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
{ "data": [ ... ], "has_more": false, "next_cursor": null }
```

Errors return a consistent envelope:

```json theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
{
  "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:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
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`:

```json theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
{ "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
  `pending` → `claimed` → `sent` (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](/guides/send-message)
for the full flow.

## Errors

The API maps to standard HTTP status codes (`2xx` success, `4xx` client error,
`5xx` server error). See [Errors](/concepts/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](/concepts/errors#rate_limit_error-429) for details.

## DELETE with a request body

`DELETE /webhooks` takes the resource ID in the **request body**, not the URL:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
curl -X DELETE https://api.messages.dev/v1/webhooks \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{"id": "wh_abc123"}'
```
