Documentation
Sign inGet started

List WhatsApp messages

GET
/v1/whatsapp/messages
for await (const msg of bird.whatsapp.list({ status: ["delivered"] })) {
  console.log(msg.id, msg.status);
}
Returns the workspace's WhatsApp messages as a cursor-paginated list, newest first, outbound and inbound alike. Each message carries the one content object it was built from: template, or free-form text, image, video, audio, sticker, document or location; an inbound message whose content WhatsApp models and we do not carries unsupported instead, naming the type rather than reading back empty. Filter by direction, status, contact phone number, business-scoped user ID, template category, tag, or creation time; pass the response's next_cursor back as starting_after to fetch the next page. To follow a single message's delivery, use Get a WhatsApp message instead.
Messages are retained for 30 days. A created_after earlier than that is accepted and raised to the retention bound rather than rejected, so a wider window returns what is still retained instead of failing. There is no way to read messages older than the window.
Query Parameters
limit
integer
Maximum number of items to return per page.
starting_after
string
Cursor from the next_cursor field of a previous list response. Returns items immediately after the cursor position in the current sort order.
ending_before
string
Cursor from the prev_cursor field of a previous list response. Returns items immediately before the cursor position in the current sort order.
created_after
string
Return only resources created at or after this timestamp (inclusive lower bound). Combine with created_before to filter to a time window. RFC 3339 / ISO 8601 with timezone.
created_before
string
Return only resources created strictly before this timestamp (exclusive upper bound). Combine with created_after to filter to a time window. RFC 3339 / ISO 8601 with timezone.
status
array
Filter by status. Repeat the parameter to match any of several statuses.
direction
string
Filter by whether the business sent the message (outbound) or received it from the contact (inbound).
Possible values: outbound, inbound
phone_number
string
Filter by contact phone number (E.164 exact match).
bsuid
string
Filter by business-scoped user ID (Meta identifier).
category
string
Filter by category.
Possible values (may grow over time): authentication, utility, marketing
tag
array
Filter by tag. Accepts name to match any message carrying that tag name, or name:value to match a specific tag pair (for example category:welcome). Repeat the parameter to add more tags. A message must match every tag listed to be returned.
Response Payload
data
array of object
required
Page of WhatsApp messages, newest first.
Show child attributes
data.id
string
required
ID of the message (wam_-prefixed), assigned when the send is accepted. Pass it as message_id to the get-message and list-events endpoints.
data.direction
string
required
Whether the message was sent by the business (outbound) or received from the contact (inbound).
Possible values: outbound, inbound
data.from
object
required
Sender of the message. On outbound messages, the business number it was sent from; on inbound, the WhatsApp contact.
Show child attributes
data.from.phone_number
string
Phone number in E.164 format, when known.
data.from.bsuid
string
Business-scoped user ID, Meta's identifier for the WhatsApp user. Present only on the WhatsApp-user side of the message.
data.to
object
required
Recipient of the message. On outbound messages, the WhatsApp contact; on inbound, the business number.
Show child attributes
data.to.phone_number
string
Phone number in E.164 format, when known.
data.to.bsuid
string
Business-scoped user ID, Meta's identifier for the WhatsApp user. Present only on the WhatsApp-user side of the message.
data.template
object
The template the message was sent from. For authentication templates the filled-in values are not returned.
Show child attributes
data.template.slug
string
required
The template's stable handle (for example bird_otp).
data.template.category
string
required
Content classification applied to messages sent from this template.
data.template.language
string
required
The canonical BCP-47 tag of the template variant that was sent.
data.template.components
array of object
required
The values that filled the template's placeholders. Empty for an authentication template, whose content is never returned.
Show child attributes
data.template.components.type
string
required
Which part of the template this fills in: body for the main text, button for a button's variable, header for the header's text, media or location, carousel for the cards.
Possible values (may grow over time): header, body, button, carousel
data.template.components.parameters
array of object
The values that fill this part's placeholders. A positional template takes them in {{n}} placeholder order; a template with named parameters requires each parameter's name to match one the template declares, and order then carries no meaning. Send it on every part except carousel, which carries its values on cards.
Show child attributes
data.template.components.parameters.type
string
required
The kind of value this parameter carries, which decides which of the fields below to send.
data.template.components.parameters.text
string
The value substituted into the placeholder, as a plain string. Send it on a text parameter.
data.template.components.parameters.url
string
Public https URL of the file a media header shows. Send it on an image, video, gif or document parameter. WhatsApp fetches it at send time, so it must still be reachable then, the same way a free-form media message's url must.
data.template.components.parameters.location
object
The point on the map a location header opens. Send it on a location parameter.
Show child attributes
data.template.components.parameters.location.latitude
number
required
Latitude in decimal degrees.
data.template.components.parameters.location.longitude
number
required
Longitude in decimal degrees.
data.template.components.parameters.location.name
string
Name of the place, shown above the address.
data.template.components.parameters.location.address
string
Street address of the place. Shown only when name is also set.
data.template.components.parameters.name
string
Required when the template declares named parameters: the placeholder this value fills (for example first_name), matching exactly one of the names the template declares. Name every parameter in that case; order does not matter once names are supplied. Omit this field for a positional template, which takes its values in {{n}} order instead. Sending the wrong set of names, or leaving one out that the template requires, returns a 422 WhatsAppTemplateParameterMismatch.
data.template.components.cards
array of object
The values that fill each card of a carousel. Send it only on a carousel part. A carousel sends exactly the number of cards its template was approved with, so every card needs an entry.
Show child attributes
data.template.components.cards.components
array of object
required
The values that fill this card's blocks.
Show child attributes
data.template.components.cards.components.type
string
required
Which part of the card this fills in: header for the card's image or video, body for its text, button for a button's variable.
Possible values (may grow over time): header, body, button
data.template.components.cards.components.parameters
array of object
The values that fill this part's placeholders, in placeholder order.
Show child attributes
data.template.components.cards.components.parameters.type
string
required
The kind of value this parameter carries, which decides which of the fields below to send.
data.template.components.cards.components.parameters.text
string
The value substituted into the placeholder, as a plain string. Send it on a text parameter.
data.template.components.cards.components.parameters.url
string
Public https URL of the file a media header shows. Send it on an image, video, gif or document parameter. WhatsApp fetches it at send time, so it must still be reachable then, the same way a free-form media message's url must.
data.template.components.cards.components.parameters.location
object
The point on the map a location header opens. Send it on a location parameter.
Show child attributes
data.template.components.cards.components.parameters.location.latitude
number
required
Latitude in decimal degrees.
data.template.components.cards.components.parameters.location.longitude
number
required
Longitude in decimal degrees.
data.template.components.cards.components.parameters.location.name
string
Name of the place, shown above the address.
data.template.components.cards.components.parameters.location.address
string
Street address of the place. Shown only when name is also set.
data.template.components.cards.components.parameters.name
string
Required when the template declares named parameters: the placeholder this value fills (for example first_name), matching exactly one of the names the template declares. Name every parameter in that case; order does not matter once names are supplied. Omit this field for a positional template, which takes its values in {{n}} order instead. Sending the wrong set of names, or leaving one out that the template requires, returns a 422 WhatsAppTemplateParameterMismatch.
data.text
object
Text the message carried.
Show child attributes
data.text.body
string
required
The message text.
data.image
object
Image the message carried.
Show child attributes
data.image.id
string
ID of the stored file, to pass as media_id when fetching it. Absent on an outbound message, whose file we never stored.
data.image.url
string
Where to fetch the media. On an inbound message this is a Bird URL you fetch with your API key; it is absent when the file could not be retrieved from WhatsApp. It stays populated after the stored bytes expire, and the link returns 410 from then on. On an outbound message it is the URL the sender supplied, whose availability is the sender's to guarantee.
data.image.mime_type
string
Media type WhatsApp reported for the file, for example image/jpeg. Absent on outbound messages.
data.image.caption
string
Text shown beneath the image. Absent when the sender wrote none.
data.video
object
Video the message carried.
Show child attributes
data.video.id
string
ID of the stored file, to pass as media_id when fetching it. Absent on an outbound message, whose file we never stored.
data.video.url
string
Where to fetch the media. On an inbound message this is a Bird URL you fetch with your API key; it is absent when the file could not be retrieved from WhatsApp. It stays populated after the stored bytes expire, and the link returns 410 from then on. On an outbound message it is the URL the sender supplied, whose availability is the sender's to guarantee.
data.video.mime_type
string
Media type WhatsApp reported for the file, for example image/jpeg. Absent on outbound messages.
data.video.caption
string
Text shown beneath the video. Absent when the sender wrote none.
data.audio
object
Audio the message carried.
Show child attributes
data.audio.id
string
ID of the stored file, to pass as media_id when fetching it. Absent on an outbound message, whose file we never stored.
data.audio.url
string
Where to fetch the media. On an inbound message this is a Bird URL you fetch with your API key; it is absent when the file could not be retrieved from WhatsApp. It stays populated after the stored bytes expire, and the link returns 410 from then on. On an outbound message it is the URL the sender supplied, whose availability is the sender's to guarantee.
data.audio.mime_type
string
Media type WhatsApp reported for the file, for example image/jpeg. Absent on outbound messages.
data.audio.voice
boolean
Whether this is a voice note rather than an attached audio file. A voice note auto-downloads in the WhatsApp client and can be transcribed for the recipient.
data.sticker
object
Sticker the message carried.
Show child attributes
data.sticker.id
string
ID of the stored file, to pass as media_id when fetching it. Absent on an outbound message, whose file we never stored.
data.sticker.url
string
Where to fetch the media. On an inbound message this is a Bird URL you fetch with your API key; it is absent when the file could not be retrieved from WhatsApp. It stays populated after the stored bytes expire, and the link returns 410 from then on. On an outbound message it is the URL the sender supplied, whose availability is the sender's to guarantee.
data.sticker.mime_type
string
Media type WhatsApp reported for the file, for example image/jpeg. Absent on outbound messages.
data.sticker.animated
boolean
Whether the sticker is animated. Absent on an outbound message.
data.document
object
Document the message carried.
Show child attributes
data.document.id
string
ID of the stored file, to pass as media_id when fetching it. Absent on an outbound message, whose file we never stored.
data.document.url
string
Where to fetch the media. On an inbound message this is a Bird URL you fetch with your API key; it is absent when the file could not be retrieved from WhatsApp. It stays populated after the stored bytes expire, and the link returns 410 from then on. On an outbound message it is the URL the sender supplied, whose availability is the sender's to guarantee.
data.document.mime_type
string
Media type WhatsApp reported for the file, for example image/jpeg. Absent on outbound messages.
data.document.caption
string
Text shown beneath the document. Absent when the sender wrote none.
data.document.filename
string
The sender's own name for the file.
data.location
object
Location the message carried.
Show child attributes
data.location.latitude
number
Latitude in decimal degrees.
data.location.longitude
number
Longitude in decimal degrees.
data.location.name
string
Name of the place. Absent when the sender shared a plain pin.
data.location.address
string
Street address of the place. Shown only when name is also set.
data.location.url
string
Link to the place, which WhatsApp includes mainly for business locations. Present on an inbound message when the sender's client supplied one, and absent on a message you sent, since sending a location does not support this field.
data.unsupported
object
Set when the contact sent content we do not model, naming the WhatsApp content type so the message is not silently empty. Inbound only.
Show child attributes
data.unsupported.type
string
required
The WhatsApp content type we did not model. unsupported is not a placeholder here: WhatsApp reports its own unsupported type for a message its own clients cannot render, and that arrives as this value. Open enum: WhatsApp adds content types over time, so treat an unrecognized value as a future type rather than an error.
Possible values (may grow over time): contacts, reaction, interactive, button, order, system, unsupported
data.status
string
required
data.last_error
nullable object
Failure detail for a message that did not reach the recipient. Present only when the message failed.
Show child attributes
data.last_error.code
string
required
Failure reason, uniform whether the failure happened internally or was reported by the WhatsApp network. insufficient_balance: the workspace could not afford the send. price_not_found: no price was configured for this destination/template combination. internal_error: an unexpected Bird-side failure. undeliverable: the recipient could not be reached (for example not on WhatsApp, or the number is invalid). service_window_expired: the 24-hour customer care window has closed and a free-form message cannot be sent; send a template instead. rate_limited: the send was throttled. recipient_suppressed: the recipient is on the workspace's suppression list; the message was rejected before sending. Open enum: new codes may be added over time, so treat any unrecognized value as a future code rather than an error.
Possible values (may grow over time): insufficient_balance, price_not_found, internal_error, undeliverable, service_window_expired, rate_limited, recipient_suppressed
data.last_error.description
string
required
Human-readable explanation of the failure.
data.last_error.meta_error_code
nullable string
Raw error code from the WhatsApp Cloud API, when available, for low-level debugging.
data.last_error.occurred_at
string
required
When the failure occurred.
data.created_at
string
required
When the message was accepted for delivery.
data.sent_at
nullable string
When the message was handed to the WhatsApp network. Null until then.
data.delivered_at
nullable string
When delivery was confirmed. Null until then.
data.read_at
nullable string
When the message was read by the recipient. Null until then.
data.cost
nullable object
What the message cost, split into Bird's charge and any third-party fees passed through. Null on an inbound message, which is never priced, on an outbound message that has not been priced yet, and on one rejected before pricing. The rate depends on the message category and the recipient's country.
Show child attributes
data.cost.amount
string
required
Total charged, as a decimal string: the sum of the components below. Net of tax, which applies to your wallet balance rather than to an individual charge.
data.cost.currency_code
string
required
ISO 4217 currency code. Every component is denominated in this currency.
data.cost.transaction_amount
nullable string
required
What Bird charged to carry the message, as a decimal string. Null when this component was not priced; "0.00000" when it priced at zero.
data.cost.passthrough_amount
nullable string
required
Third-party fees Bird passes on, as a decimal string, such as US 10DLC carrier surcharges. Null when this component was not priced; "0.00000" when it priced at zero.
data.tags
array of object
Structured {name, value} filter labels applied to this message.
Show child attributes
data.tags.name
string
required
Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.
data.tags.value
string
required
Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.
data.metadata
object
Arbitrary JSON metadata stored on the message.
next_cursor
nullable string
required
Cursor for the next page. Pass back as starting_after to advance forward. Null when no next page exists.
prev_cursor
nullable string
required
Cursor for the previous page. Pass back as ending_before to step backward. Null when no previous page exists.
refresh_cursor
nullable string
required
Refresh anchor. Pass back as ending_before later to fetch items that have appeared since this response. Non-null whenever data is non-empty; null only on an empty page. Distinct from prev_cursor.