Sign inGet started

Receiving WhatsApp documents

A PDF, spreadsheet, or any other file a contact attaches arrives as an inbound message carrying document: the shared media reference, plus the name their own device gave the file.

What an inbound document carries

Ejemplo de código
{
  "id": "wam_01kyd6s0qfxv8t4k7n1yze6rhc",
  "direction": "inbound",
  "from": { "phone_number": "+14155550100" },
  "to": { "phone_number": "+13124495569" },
  "status": "received",
  "document": {
    "id": "waf_01kyd5p6zs9yju2f0p5rtx8vgb",
    "url": "https://platform.bird.com/v1/whatsapp/messages/wam_01kyd6s0qfxv8t4k7n1yze6rhc/media/waf_01kyd5p6zs9yju2f0p5rtx8vgb",
    "mime_type": "application/pdf",
    "filename": "invoice-A1B2C3.pdf"
  },
  "created_at": "2026-08-25T09:15:02Z"
}
FieldWhat it carries
idThe stored file, to pass as media_id when fetching the bytes
urlA Bird URL, fetched with your API key
mime_typeThe media type WhatsApp reported for the file, such as application/pdf
filenameThe sender's own name for the file; absent when the message carried none
captionThe text the contact typed under the document; absent when they sent none
filename is the one field the sending side and the receiving side use differently: on a send it is the name you want shown in the chat, and on an inbound message it is whatever the contact's device supplied.

Fetching the bytes

Pass the message ID and the media id to the channel's media method. The hub's fetching inbound media carries that call in every language, along with the redirect and header rules it follows, and owns the retention window the file lives in.
Do not write filename to disk as it arrives. It is attacker-controlled text from an unauthenticated sender: it can carry path separators, traversal sequences, a misleading second extension, or a name that collides with a file you already hold. Generate your own storage key from the media id, keep filename as a display label, and decide what to do with the file from mime_type rather than from the extension the name claims.

The webhook payload

whatsapp.received carries the document arm on the event envelope:
Ejemplo de código
{
  "type": "whatsapp.received",
  "timestamp": "2026-08-25T09:15:02.336Z",
  "data": {
    "whatsapp_id": "wam_01kyd6s0qfxv8t4k7n1yze6rhc",
    "workspace_id": "ws_01ky7m235keycbnwyajabe1a6b",
    "direction": "inbound",
    "from": { "phone_number": "+14155550100" },
    "to": { "phone_number": "+13124495569" },
    "document": {
      "id": "waf_01kyd5p6zs9yju2f0p5rtx8vgb",
      "url": "https://platform.bird.com/v1/whatsapp/messages/wam_01kyd6s0qfxv8t4k7n1yze6rhc/media/waf_01kyd5p6zs9yju2f0p5rtx8vgb",
      "mime_type": "application/pdf",
      "filename": "invoice-A1B2C3.pdf"
    },
    "tags": null,
    "metadata": null
  }
}
A claims or onboarding flow that collects paperwork can route on mime_type here and queue the fetch, since the bytes stay available for the whole retention window.

Things to watch

  • mime_type is WhatsApp's report on the file, and says nothing about what is inside it. Scan anything you accept from a contact, and validate the file's own structure before parsing it.
  • A caption and a filename are different fields. A contact who types a note when attaching the file fills caption; filename still comes off their device.

Next steps