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

# Quickstart

> Send your first iMessage in 5 minutes

## 1. Create an account & get your API key

Sign up at [app.messages.dev](https://app.messages.dev), then go to **API Keys** in the sidebar and click **Create Key**. Copy the key. It starts with `sk_live_` and is only shown once.

<Warning>
  Store your API key somewhere safe. It won't be displayed again. If you lose it, revoke it from the dashboard and create a new one.
</Warning>

## 2. Activate your sandbox

Go to the **Lines** page in your dashboard. You'll see a sandbox card with a QR code and an activation code. Scan the QR code with your phone (it opens a pre-filled text message) or manually text the code to the sandbox number.

Once your message is received, your sandbox is activated and your phone number is paired. You get **50 free messages per day**.

<Info>
  The sandbox is a shared iMessage line for testing. For production use, set up a dedicated line.
</Info>

## 3. Install the SDK (optional)

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

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

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

  ```bash bun theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  bun add @messages-dev/sdk
  ```
</CodeGroup>

<Info>
  The SDK is optional. You can use any HTTP client or `curl` instead. All examples below show both.
</Info>

## 4. Send a message

Every message is sent **from** a line. If you activated the sandbox, use the sandbox line handle and your paired phone number. You can find your line handle on the **Lines** page in the dashboard.

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  import { createClient } from "@messages-dev/sdk";

  const client = createClient();

  await client.sendMessage({
    from: "+15551234567",
    to: "+15559876543",
    text: "Hello from Messages.dev!",
  });
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  curl -X POST "https://api.messages.dev/v1/messages" \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "from": "+15551234567",
      "to": "+15559876543",
      "text": "Hello from Messages.dev!"
    }'
  ```
</CodeGroup>

That's it. Your first message is on its way.

## 5. Receive messages

### Local development: use the CLI

The fastest way to receive messages while you're building is the
[`messages-dev` CLI](/cli). It streams events from your account and POSTs
them at a local URL with the same HMAC headers production webhooks use, so
you can develop and test your handler without ngrok, a public URL, or a
registered webhook.

[Install the CLI and authenticate](/cli#install), then:

```sh theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
messages-dev listen --forward-to http://localhost:3000/webhooks
```

The CLI prints a per-session HMAC secret on first run. Use it as your
webhook secret in development, or pin one with `MESSAGES_LISTEN_SECRET=…`.

<Note>
  Prefer the standard webhook path? Expose your local server with
  [ngrok](https://ngrok.com), Cloudflare Tunnel, or any tunnel of your
  choice and register a real webhook pointing at the public URL. The
  handler code below is identical either way. See
  [Receive Messages](/guides/receive-messages) for the full breakdown.
</Note>

Then handle incoming events on your server exactly as you would in
production:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
import { verifyWebhook } from "@messages-dev/sdk";

app.post("/webhooks", async (req, res) => {
  const event = await verifyWebhook(
    req.body,
    req.headers["x-webhook-signature"],
    process.env.WEBHOOK_SECRET!,
  );

  if (event.event === "message.received") {
    console.log(`${event.data.sender}: ${event.data.text}`);
  }

  res.sendStatus(200);
});
```

### Production: register a webhook

For production, [register a webhook](/concepts/webhooks#creating-a-webhook)
so messages.dev delivers events directly to your public URL. The handler
code above is unchanged; only the secret and the source of the deliveries
differ. See [Webhooks](/concepts/webhooks) for the full event list, payload
shapes, and signature verification details.

## 6. List your lines (optional)

If you need to look up your line handles programmatically:

<CodeGroup>
  ```typescript TypeScript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  await client.listLines();
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  curl https://api.messages.dev/v1/lines \
    -H "Authorization: Bearer sk_live_..."
  ```
</CodeGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Send Messages" icon="paper-plane" href="/guides/send-message">
    Delivery tracking and error handling
  </Card>

  <Card title="Receive Messages" icon="inbox" href="/guides/receive-messages">
    Webhooks for real-time message delivery
  </Card>

  <Card title="TypeScript SDK" icon="js" href="/sdk">
    Full SDK reference: pagination, error handling, types
  </Card>

  <Card title="API Reference" icon="code" href="/api-reference/overview">
    All endpoints
  </Card>
</CardGroup>
