Skip to content

Enriched message.received webhooks

Released: June 15, 2026

message.received deliveries still use the Meta passthrough envelope (object + entry[]) so existing parsers keep working unchanged. A new optional top-level kirim block adds Kirimdev routing context:

  • conversation_id, contact_id, message_id, phone_number_id
  • labels[] — conversation labels at delivery time
  • conversation.status, conversation.assigned_to
  • contact.name, contact.phone_number (E.164 with +)
  • media_url — permanent https://media.kirimdev.com/... URL when the asset is ready (null for text messages)
  • media_statusready, failed, unavailable, or null for text

Delivery timing

  • Text and other non-media messages — webhook fires immediately (same latency as before).
  • Inbound media (image, video, audio, document, sticker) — webhook waits until the file is uploaded to Kirimdev storage so kirim.media_url is populated on the first delivery (~1–3 seconds typical). If the download exhausts retries, the webhook still fires with media_status: "failed" and media_url: null — use GET /v1/{phone_number_id}/messages/{message_id}/media as a fallback.

The Meta entry[] shape is unchanged. Media bytes are not inlined in the Meta image / document object — only id and mime_type, same as Meta’s native webhook contract.

MetaPassthroughBody and MessageReceivedKirimContext are exported from @kirimdev/sdk/webhooks. The kirim field is optional — strict Meta-only parsers can ignore it.