Documentation
Sign inGet started

WhatsApp audio messages

An audio message carries a public URL WhatsApp fetches at send time. It has no caption, and it can optionally render as a voice note.

Send an audio message

Set audio.url:
const msg = await bird.whatsapp.send({
  to: "+16505551234",
  from: "+13124495648",
  audio: { url: "https://cdn.example.com/vm/9f2.ogg" },
});
console.log(msg.id, msg.status);
The full shape adds the optional voice flag, the only other field audio has:
Exemple de code
{
  "to": "+16505551234",
  "from": "+13124495648",
  "audio": { "url": "https://cdn.example.com/voice/9f2e4a.ogg", "voice": true }
}
audio has no caption field at all. from is required on every service message: a number your workspace owns, not a Bird-managed one.

Limits

FieldBoundEnforced by
File size16 MBWhatsApp only, at fetch (async)
FormatAAC, AMR, MP3, M4A, or OGG with the OPUS codec, monoWhatsApp only, at fetch (async)
voice: truerequires .ogg/OPUS, mono; other formats make transcription failWhatsApp only, at fetch (async)
captionnot a valid fieldBird, at accept (422, schema rejection)
urlabsolute, https, has a host, no raw spaceBird, at accept (422)
Bird checks the URL's shape before anything is enqueued; it does not check the file's actual size, format, or codec, and it does not check that a voice: true send is actually .ogg/OPUS. Only WhatsApp's own fetch at send time can. Sending a caption on an audio message is not a length error; the field doesn't exist on this arm's schema, so it fails as an unrecognized property. See the hub's sending media by URL and when media fails.

Reading an inbound audio message

An inbound audio message carries the same audio object, plus an id and mime_type Bird learned by fetching the file:
Exemple de code
{
  "id": "wam_01kya2b7fmqvs1t4d9n3p6xwjh",
  "direction": "inbound",
  "from": { "phone_number": "+14155550100" },
  "to": { "phone_number": "+13124495569" },
  "audio": {
    "id": "waf_01kyb2m4xq7whs0d8n3prv6tez",
    "url": "https://platform.bird.com/v1/whatsapp/messages/wam_01kya2b7fmqvs1t4d9n3p6xwjh/media/waf_01kyb2m4xq7whs0d8n3prv6tez",
    "mime_type": "audio/ogg",
    "voice": true
  },
  "status": "received"
}
There is no caption on read either. To fetch the bytes behind an inbound audio message, see Receiving WhatsApp messages.

Limits and failure modes

  • The customer service window has to be open. Audio is a service message, deliverable only inside an open window; see the hub's customer service window.
  • Bird rejects http; WhatsApp itself would fetch it. See the hub's sending media by URL for the full shape check.
  • A rejected fetch still gets charged. See the hub's when media fails. Audio's own rejection text from WhatsApp hasn't been independently measured, so treat the mapping as inferred by symmetry rather than confirmed per cause.
  • The voice flag changes how the recipient's client renders the message, not what Bird validates. voice: true renders it as a voice note: it auto-downloads, shows an inline microphone icon, and can be transcribed. Getting that right needs a .ogg file encoded with OPUS, mono; any other format still sends, but transcription fails on the recipient's end. voice defaults to false.
  • WhatsApp's own play-icon threshold and "played" signal aren't something Bird surfaces. WhatsApp documents a client behavior around small voice notes and a played state, but Bird models neither; don't build an integration that expects to read either back from the API.
  • WhatsApp caches a fetched URL for about 10 minutes. Resending the identical URL inside that window re-serves the first fetch; vary the URL to force a fresh one.

Next steps