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

# Attachments

> Send images, files, and other attachments

You can send images, videos, documents, and other files as iMessage attachments.
Incoming messages with attachments include metadata and a download URL for each file.

## Send an attachment

Upload a file first, then reference it by ID when sending a message:

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

  const client = createClient();

  const file = await client.uploadFile({
    from: "+15551234567",
    file: Buffer.from(imageData),
    filename: "photo.jpg",
    mimeType: "image/jpeg",
  });

  await client.sendMessage({
    from: "+15551234567",
    to: "+15559876543",
    text: "Check out this photo!",
    attachments: [file.id],
  });

  await client.sendMessage({
    from: "+15551234567",
    to: "+15559876543",
    attachments: [file.id],
  });
  ```

  ```bash curl theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
  curl -X POST "https://api.messages.dev/v1/files?from=+15551234567" \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: image/jpeg" \
    -H "X-Filename: photo.jpg" \
    --data-binary @photo.jpg

  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": "Check out this photo!",
      "attachments": ["file_abc123"]
    }'
  ```
</CodeGroup>

| Field         | Required | Description                                                |
| ------------- | -------- | ---------------------------------------------------------- |
| `to`          | Yes      | Recipient phone number or Apple ID                         |
| `text`        | No       | Optional message text (can be omitted when sending a file) |
| `attachments` | No       | Array of file IDs (max 1) from the upload endpoint         |

<Note>
  At least one of `text` or `attachments` must be provided.
</Note>

## Supported file types

iMessage supports most common file types. The recipient's device determines how
the attachment is displayed:

| Type      | Examples                                 | Display                 |
| --------- | ---------------------------------------- | ----------------------- |
| Images    | `.jpg`, `.png`, `.gif`, `.heic`, `.webp` | Inline preview          |
| Videos    | `.mp4`, `.mov`                           | Inline player           |
| Audio     | `.mp3`, `.m4a`, `.aac`                   | Audio player            |
| Documents | `.pdf`, `.docx`, `.xlsx`                 | File icon with preview  |
| Other     | Any file type                            | Generic file attachment |

## Receive attachments

Incoming messages with attachments include an `attachments` array with metadata
and a download URL for each file:

```json theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
{
  "event": "message.received",
  "data": {
    "id": "msg_abc123",
    "sender": "+15559876543",
    "text": null,
    "attachments": [
      {
        "filename": "IMG_1234.jpg",
        "mime_type": "image/jpeg",
        "size": 245760,
        "url": "https://storage.convex.cloud/..."
      }
    ],
    "sent_at": 1710000005000
  }
}
```

Handle attachments in your webhook:

```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"],
    "your_webhook_secret",
  );

  if (event.event === "message.received") {
    if (event.data.attachments?.length) {
      for (const att of event.data.attachments) {
        console.log(`Received: ${att.filename} (${att.mimeType}, ${att.size} bytes)`);
        console.log(`Download: ${att.url}`);
      }
    }

    if (event.data.text) {
      console.log(`Text: ${event.data.text}`);
    }
  }

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

You can also retrieve attachment URLs when listing messages:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-high-contrast"}}
const messages = await client.listMessages({
  from: "+15551234567",
  to: "+15559876543",
});

for (const msg of messages.data) {
  for (const att of msg.attachments) {
    console.log(att.url);
    console.log(att.filename);
    console.log(att.mimeType);
  }
}
```
