Skip to main content
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:
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],
});
FieldRequiredDescription
toYesRecipient phone number or Apple ID
textNoOptional message text (can be omitted when sending a file)
attachmentsNoArray of file IDs (max 1) from the upload endpoint
At least one of text or attachments must be provided.

Supported file types

iMessage supports most common file types. The recipient’s device determines how the attachment is displayed:
TypeExamplesDisplay
Images.jpg, .png, .gif, .heic, .webpInline preview
Videos.mp4, .movInline player
Audio.mp3, .m4a, .aacAudio player
Documents.pdf, .docx, .xlsxFile icon with preview
OtherAny file typeGeneric file attachment

Receive attachments

Incoming messages with attachments include an attachments array with metadata and a download URL for each file:
{
  "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:
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:
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);
  }
}