# WhaBuzz developer documentation > WhaBuzz is a WhatsApp Cloud API gateway for businesses and platforms in India. Send Meta's own message bodies to api.whabuzz.com, receive signed webhooks with the full Meta payload, retries and replay. Flat monthly fee per number, never per message. Generated 2026-10-15 from https://docs.whabuzz.com. One section per page. ======================================================================== Source: https://docs.whabuzz.com/events/inbound-text/ ======================================================================== # Inbound text > A customer typed a message. data.message.text.body is the text. Replies carry context.id, the wamid of the message being replied to; forwarded messages carry context.forwarded; messages that start fro Canonical: https://docs.whabuzz.com/events/inbound-text/ A customer typed a message. `data.message.text.body` is the text. Replies carry `context.id`, the wamid of the message being replied to; forwarded messages carry `context.forwarded`; messages that start from a click-to-WhatsApp ad carry `referral` with the ad identifiers. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Plain text {#text} What Meta POSTs to WhaBuzz (`fixtures/meta/text.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB01AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "Hi, is the 7am batch open tomorrow?" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB01AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB01AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB01AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "Hi, is the 7am batch open tomorrow?" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ## A reply to an earlier message (`context`) {#text-reply-context} What Meta POSTs to WhaBuzz (`fixtures/meta/text_reply_context.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB02AA=", "timestamp": "1760591523", "type": "text", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB90AA=" }, "text": { "body": "Yes, book me in" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB02AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB02AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB02AA=", "timestamp": "1760591523", "type": "text", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB90AA=" }, "text": { "body": "Yes, book me in" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ## Forwarded text (`context.forwarded`) {#text-forwarded} What Meta POSTs to WhaBuzz (`fixtures/meta/text_forwarded.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB03AA=", "timestamp": "1760591523", "type": "text", "context": { "forwarded": true, "frequently_forwarded": true }, "text": { "body": "Forwarded many times" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB03AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB03AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB03AA=", "timestamp": "1760591523", "type": "text", "context": { "forwarded": true, "frequently_forwarded": true }, "text": { "body": "Forwarded many times" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ## From a click-to-WhatsApp ad (`referral`) {#text-referral-ctwa} What Meta POSTs to WhaBuzz (`fixtures/meta/text_referral_ctwa.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB04AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "I saw your ad" }, "referral": { "source_url": "https://fb.me/3cr4Wqqkv", "source_id": "120214567890123456", "source_type": "ad", "body": "Book a free trial", "headline": "Trial class", "media_type": "image", "image_url": "https://scontent.xx.fbcdn.net/v/t45.1600-4/ad.jpg", "ctwa_clid": "ARAkLkA8rmlFeiCktEJQ-QTwRiyYHAFDLMNDBH0CD3qpjd0HR4irJ6LEkR7JwFF4XvnO2E4Nx0-eM-GABDLOPaOdRMv-_zfUQ2a", "welcome_message": { "text": "Hi! Tap send to ask about the trial." } } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB04AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB04AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB04AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "I saw your ad" }, "referral": { "source_url": "https://fb.me/3cr4Wqqkv", "source_id": "120214567890123456", "source_type": "ad", "body": "Book a free trial", "headline": "Trial class", "media_type": "image", "image_url": "https://scontent.xx.fbcdn.net/v/t45.1600-4/ad.jpg", "ctwa_clid": "ARAkLkA8rmlFeiCktEJQ-QTwRiyYHAFDLMNDBH0CD3qpjd0HR4irJ6LEkR7JwFF4XvnO2E4Nx0-eM-GABDLOPaOdRMv-_zfUQ2a", "welcome_message": { "text": "Hi! Tap send to ask about the trial." } } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-image/ ======================================================================== # Inbound image > An image. Meta sends a media id, not bytes. Fetch the bytes with GET /v1/media/{media_id}(/api/media/#downloadMedia) before Meta expires the media. Canonical: https://docs.whabuzz.com/events/inbound-image/ An image. Meta sends a media `id`, not bytes. Fetch the bytes with [`GET /v1/media/{media_id}`](https://docs.whabuzz.com/api/media.md#downloadMedia) before Meta expires the media. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Image with caption {#image} What Meta POSTs to WhaBuzz (`fixtures/meta/image.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB05AA=", "timestamp": "1760591523", "type": "image", "image": { "caption": "My form check", "mime_type": "image/jpeg", "sha256": "aBcDeF0123456789aBcDeF0123456789aBcDeF012345=", "id": "1479537139650973" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB05AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB05AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB05AA=", "timestamp": "1760591523", "type": "image", "image": { "caption": "My form check", "mime_type": "image/jpeg", "sha256": "aBcDeF0123456789aBcDeF0123456789aBcDeF012345=", "id": "1479537139650973" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-video/ ======================================================================== # Inbound video > A video. Same media-id mechanics as images: download through GET /v1/media/{media_id}(/api/media/#downloadMedia). Canonical: https://docs.whabuzz.com/events/inbound-video/ A video. Same media-id mechanics as images: download through [`GET /v1/media/{media_id}`](https://docs.whabuzz.com/api/media.md#downloadMedia). **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Video with caption {#video} What Meta POSTs to WhaBuzz (`fixtures/meta/video.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB06AA=", "timestamp": "1760591523", "type": "video", "video": { "caption": "Squat set", "mime_type": "video/mp4", "sha256": "q0w9e8r7t6y5u4i3o2p1a2s3d4f5g6h7j8k9l0z9x8c=", "id": "1146497596886432" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB06AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB06AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB06AA=", "timestamp": "1760591523", "type": "video", "video": { "caption": "Squat set", "mime_type": "video/mp4", "sha256": "q0w9e8r7t6y5u4i3o2p1a2s3d4f5g6h7j8k9l0z9x8c=", "id": "1146497596886432" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-audio/ ======================================================================== # Inbound audio and voice notes > Audio. audio.voice is true for a recorded voice note. Download through GET /v1/media/{media_id}(/api/media/#downloadMedia). Canonical: https://docs.whabuzz.com/events/inbound-audio/ Audio. `audio.voice` is `true` for a recorded voice note. Download through [`GET /v1/media/{media_id}`](https://docs.whabuzz.com/api/media.md#downloadMedia). **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Voice note (`voice: true`) {#audio-voice} What Meta POSTs to WhaBuzz (`fixtures/meta/audio_voice.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB07AA=", "timestamp": "1760591523", "type": "audio", "audio": { "mime_type": "audio/ogg; codecs=opus", "sha256": "m1n2b3v4c5x6z7l8k9j0h1g2f3d4s5a6p7o8i9u0y1t=", "id": "1003383421387256", "voice": true } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB07AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB07AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB07AA=", "timestamp": "1760591523", "type": "audio", "audio": { "mime_type": "audio/ogg; codecs=opus", "sha256": "m1n2b3v4c5x6z7l8k9j0h1g2f3d4s5a6p7o8i9u0y1t=", "id": "1003383421387256", "voice": true } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-document/ ======================================================================== # Inbound document > A file. document.filename and document.mime_type describe it; download through GET /v1/media/{media_id}(/api/media/#downloadMedia). Canonical: https://docs.whabuzz.com/events/inbound-document/ A file. `document.filename` and `document.mime_type` describe it; download through [`GET /v1/media/{media_id}`](https://docs.whabuzz.com/api/media.md#downloadMedia). **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## PDF with filename and caption {#document} What Meta POSTs to WhaBuzz (`fixtures/meta/document.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB08AA=", "timestamp": "1760591523", "type": "document", "document": { "caption": "Medical clearance", "filename": "clearance.pdf", "mime_type": "application/pdf", "sha256": "z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e=", "id": "1356208412297128" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB08AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB08AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB08AA=", "timestamp": "1760591523", "type": "document", "document": { "caption": "Medical clearance", "filename": "clearance.pdf", "mime_type": "application/pdf", "sha256": "z9y8x7w6v5u4t3s2r1q0p9o8n7m6l5k4j3i2h1g0f9e=", "id": "1356208412297128" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-sticker/ ======================================================================== # Inbound sticker > A sticker. sticker.animated tells you whether it moves. Canonical: https://docs.whabuzz.com/events/inbound-sticker/ A sticker. `sticker.animated` tells you whether it moves. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Static sticker {#sticker} What Meta POSTs to WhaBuzz (`fixtures/meta/sticker.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB09AA=", "timestamp": "1760591523", "type": "sticker", "sticker": { "mime_type": "image/webp", "sha256": "s1t2i3c4k5e6r7s8h9a0s1h2v3a4l5u6e7x8y9z0a1b=", "id": "1229145238394866", "animated": false } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB09AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB09AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB09AA=", "timestamp": "1760591523", "type": "sticker", "sticker": { "mime_type": "image/webp", "sha256": "s1t2i3c4k5e6r7s8h9a0s1h2v3a4l5u6e7x8y9z0a1b=", "id": "1229145238394866", "animated": false } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-location/ ======================================================================== # Inbound location > A shared location with coordinates and optional name and address. Canonical: https://docs.whabuzz.com/events/inbound-location/ A shared location with coordinates and optional name and address. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Shared location {#location} What Meta POSTs to WhaBuzz (`fixtures/meta/location.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB10AA=", "timestamp": "1760591523", "type": "location", "location": { "address": "Kokapet, Hyderabad, Telangana", "latitude": 17.3953, "longitude": 78.3363, "name": "Home", "url": "https://maps.example.com/p/123" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB10AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB10AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB10AA=", "timestamp": "1760591523", "type": "location", "location": { "address": "Kokapet, Hyderabad, Telangana", "latitude": 17.3953, "longitude": 78.3363, "name": "Home", "url": "https://maps.example.com/p/123" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-contacts/ ======================================================================== # Inbound contact cards > One or more shared contact cards. Note the two contacts keys: data.contacts is the sender profile Meta attaches to every webhook, data.message.contacts is the card the customer shared. Canonical: https://docs.whabuzz.com/events/inbound-contacts/ One or more shared contact cards. Note the two `contacts` keys: `data.contacts` is the sender profile Meta attaches to every webhook, `data.message.contacts` is the card the customer shared. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## A shared contact card {#contacts} What Meta POSTs to WhaBuzz (`fixtures/meta/contacts.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB11AA=", "timestamp": "1760591523", "type": "contacts", "contacts": [ { "addresses": [ { "city": "Hyderabad", "country": "India", "country_code": "IN", "state": "TS", "street": "1 Example Road", "type": "HOME", "zip": "500075" } ], "birthday": "1990-01-31", "emails": [ { "email": "friend@example.com", "type": "WORK" } ], "name": { "first_name": "Ravi", "formatted_name": "Ravi Kumar", "last_name": "Kumar" }, "org": { "company": "Example Co", "department": "Ops", "title": "Lead" }, "phones": [ { "phone": "+1 650-555-1235", "wa_id": "16505551235", "type": "CELL" } ], "urls": [ { "url": "https://example.com", "type": "WORK" } ] } ] } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB11AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB11AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB11AA=", "timestamp": "1760591523", "type": "contacts", "contacts": [ { "addresses": [ { "city": "Hyderabad", "country": "India", "country_code": "IN", "state": "TS", "street": "1 Example Road", "type": "HOME", "zip": "500075" } ], "birthday": "1990-01-31", "emails": [ { "email": "friend@example.com", "type": "WORK" } ], "name": { "first_name": "Ravi", "formatted_name": "Ravi Kumar", "last_name": "Kumar" }, "org": { "company": "Example Co", "department": "Ops", "title": "Lead" }, "phones": [ { "phone": "+1 650-555-1235", "wa_id": "16505551235", "type": "CELL" } ], "urls": [ { "url": "https://example.com", "type": "WORK" } ] } ] } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-button-reply/ ======================================================================== # Inbound interactive button reply > The customer tapped a reply button on an interactive message you sent. context.id is the wamid of that message. Canonical: https://docs.whabuzz.com/events/inbound-button-reply/ The customer tapped a reply button on an interactive message you sent. `context.id` is the wamid of that message. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Reply-button tap {#interactive-button-reply} What Meta POSTs to WhaBuzz (`fixtures/meta/interactive_button_reply.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB12AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB91AA=" }, "interactive": { "type": "button_reply", "button_reply": { "id": "confirm_yes", "title": "Yes, confirm" } } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB12AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB12AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB12AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB91AA=" }, "interactive": { "type": "button_reply", "button_reply": { "id": "confirm_yes", "title": "Yes, confirm" } } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-list-reply/ ======================================================================== # Inbound interactive list reply > The customer chose a row from an interactive list message. Canonical: https://docs.whabuzz.com/events/inbound-list-reply/ The customer chose a row from an interactive list message. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## List row chosen {#interactive-list-reply} What Meta POSTs to WhaBuzz (`fixtures/meta/interactive_list_reply.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB13AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB92AA=" }, "interactive": { "type": "list_reply", "list_reply": { "id": "slot_0700", "title": "7:00 AM", "description": "Strength, Coach Anil" } } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB13AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB13AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB13AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB92AA=" }, "interactive": { "type": "list_reply", "list_reply": { "id": "slot_0700", "title": "7:00 AM", "description": "Strength, Coach Anil" } } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-flow-reply/ ======================================================================== # Inbound Flow response (nfm_reply) > The customer submitted a WhatsApp Flow. interactive.nfm_reply.response_json is a JSON string, exactly as Meta sends it; parse it on your side. Canonical: https://docs.whabuzz.com/events/inbound-flow-reply/ The customer submitted a WhatsApp Flow. `interactive.nfm_reply.response_json` is a JSON string, exactly as Meta sends it; parse it on your side. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Flow submission {#interactive-nfm-reply} What Meta POSTs to WhaBuzz (`fixtures/meta/interactive_nfm_reply.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB14AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB93AA=" }, "interactive": { "type": "nfm_reply", "nfm_reply": { "response_json": "{\"flow_token\":\"abc\",\"slot\":\"0700\"}", "body": "Sent", "name": "flow" } } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB14AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB14AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB14AA=", "timestamp": "1760591523", "type": "interactive", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB93AA=" }, "interactive": { "type": "nfm_reply", "nfm_reply": { "response_json": "{\"flow_token\":\"abc\",\"slot\":\"0700\"}", "body": "Sent", "name": "flow" } } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-template-button/ ======================================================================== # Inbound template quick-reply button > The customer tapped a quick-reply button on a template message. button.payload is the payload you set when you created the template. Canonical: https://docs.whabuzz.com/events/inbound-template-button/ The customer tapped a quick-reply button on a template message. `button.payload` is the payload you set when you created the template. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Quick-reply tap on a template {#button-template-quick-reply} What Meta POSTs to WhaBuzz (`fixtures/meta/button_template_quick_reply.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB15AA=", "timestamp": "1760591523", "type": "button", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB94AA=" }, "button": { "payload": "RENEW_YES", "text": "Renew now" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB15AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB15AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB15AA=", "timestamp": "1760591523", "type": "button", "context": { "from": "14692311132", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB94AA=" }, "button": { "payload": "RENEW_YES", "text": "Renew now" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-reaction/ ======================================================================== # Inbound reaction > An emoji reaction to one of your messages. reaction.message_id is the wamid reacted to. Canonical: https://docs.whabuzz.com/events/inbound-reaction/ An emoji reaction to one of your messages. `reaction.message_id` is the wamid reacted to. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Emoji reaction {#reaction} What Meta POSTs to WhaBuzz (`fixtures/meta/reaction.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB16AA=", "timestamp": "1760591523", "type": "reaction", "reaction": { "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB95AA=", "emoji": "👍" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB16AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB16AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB16AA=", "timestamp": "1760591523", "type": "reaction", "reaction": { "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB95AA=", "emoji": "👍" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-order/ ======================================================================== # Inbound order > A cart the customer sent from your catalog. Canonical: https://docs.whabuzz.com/events/inbound-order/ A cart the customer sent from your catalog. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Cart sent from a catalog {#order} What Meta POSTs to WhaBuzz (`fixtures/meta/order.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB17AA=", "timestamp": "1760591523", "type": "order", "order": { "catalog_id": "1234567890123456", "text": "Please deliver by Friday", "product_items": [ { "product_retailer_id": "SKU-PROTEIN-1KG", "quantity": 2, "item_price": 2499, "currency": "INR" } ] } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB17AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB17AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB17AA=", "timestamp": "1760591523", "type": "order", "order": { "catalog_id": "1234567890123456", "text": "Please deliver by Friday", "product_items": [ { "product_retailer_id": "SKU-PROTEIN-1KG", "quantity": 2, "item_price": 2499, "currency": "INR" } ] } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-unsupported/ ======================================================================== # Inbound unsupported message > Meta could not deliver the content. The message arrives with type: "unsupported" and a message-level errors. It is still a message.inbound event; nothing is dropped. Canonical: https://docs.whabuzz.com/events/inbound-unsupported/ Meta could not deliver the content. The message arrives with `type: "unsupported"` and a message-level `errors[]`. It is still a `message.inbound` event; nothing is dropped. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Message type Meta cannot deliver {#unsupported} What Meta POSTs to WhaBuzz (`fixtures/meta/unsupported.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB18AA=", "timestamp": "1760591523", "type": "unsupported", "errors": [ { "code": 131051, "title": "Message type unknown", "message": "Message type unknown", "error_data": { "details": "Message type is currently not supported." } } ], "unsupported": { "type": "edit" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB18AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB18AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB18AA=", "timestamp": "1760591523", "type": "unsupported", "errors": [ { "code": 131051, "title": "Message type unknown", "message": "Message type unknown", "error_data": { "details": "Message type is currently not supported." } } ], "unsupported": { "type": "edit" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/inbound-system/ ======================================================================== # Inbound system message > Meta system notices arrive as type: "system". This one says the customer moved to a new number; system.wa_id is the new id. Canonical: https://docs.whabuzz.com/events/inbound-system/ Meta system notices arrive as `type: "system"`. This one says the customer moved to a new number; `system.wa_id` is the new id. **Event type:** `message.inbound`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Customer changed their number {#system-user-changed-number} What Meta POSTs to WhaBuzz (`fixtures/meta/system_user_changed_number.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB19AA=", "timestamp": "1760591523", "type": "system", "system": { "body": "User A changed from 16505551234 to 16505559999", "wa_id": "16505559999", "type": "user_changed_number" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB19AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB19AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB19AA=", "timestamp": "1760591523", "type": "system", "system": { "body": "User A changed from 16505551234 to 16505559999", "wa_id": "16505559999", "type": "user_changed_number" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/message-status/ ======================================================================== # Message status > The delivery lifecycle of a message you sent: sent, delivered, read, or failed. status.errors on a failure is Meta's array untouched; see Errors(/errors/#reading-meta-errors). One Meta POST that conta Canonical: https://docs.whabuzz.com/events/message-status/ The delivery lifecycle of a message you sent: `sent`, `delivered`, `read`, or `failed`. `status.errors[]` on a failure is Meta's array untouched; see [Errors](https://docs.whabuzz.com/errors.md#reading-meta-errors). One Meta POST that contains several statuses becomes one event per status, and each event carries the same `raw`. Order is not guaranteed; order by `status.timestamp`. **Event type:** `message.status`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## sent {#status-sent} What Meta POSTs to WhaBuzz (`fixtures/meta/status_sent.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB40AA=", "status": "sent", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "conversation": { "id": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "expiration_timestamp": "1760677923", "origin": { "type": "utility" } }, "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB40AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB40AA=:sent:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB40AA=", "status": "sent", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "conversation": { "id": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "expiration_timestamp": "1760677923", "origin": { "type": "utility" } }, "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` ## delivered (with `conversation` and `pricing`) {#status-delivered} What Meta POSTs to WhaBuzz (`fixtures/meta/status_delivered.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB41AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "conversation": { "id": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "expiration_timestamp": "1760677923", "origin": { "type": "marketing" } }, "pricing": { "billable": true, "pricing_model": "PMP", "category": "marketing", "type": "regular" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB41AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB41AA=:delivered:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB41AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "conversation": { "id": "a1b2c3d4e5f60718293a4b5c6d7e8f90", "expiration_timestamp": "1760677923", "origin": { "type": "marketing" } }, "pricing": { "billable": true, "pricing_model": "PMP", "category": "marketing", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` ## read (free service conversation) {#status-read} What Meta POSTs to WhaBuzz (`fixtures/meta/status_read.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB42AA=", "status": "read", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": false, "pricing_model": "PMP", "category": "service", "type": "free_customer_service" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB42AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB42AA=:read:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB42AA=", "status": "read", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": false, "pricing_model": "PMP", "category": "service", "type": "free_customer_service" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` ## failed {#status-failed} What Meta POSTs to WhaBuzz (`fixtures/meta/status_failed.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB43AA=", "status": "failed", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "errors": [ { "code": 131049, "title": "This message was not delivered to maintain healthy ecosystem engagement.", "message": "This message was not delivered to maintain healthy ecosystem engagement.", "error_data": { "details": "In order to maintain a healthy ecosystem engagement, the message failed to be delivered." }, "href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/" } ] } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB43AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB43AA=:failed:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB43AA=", "status": "failed", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "errors": [ { "code": 131049, "title": "This message was not delivered to maintain healthy ecosystem engagement.", "message": "This message was not delivered to maintain healthy ecosystem engagement.", "error_data": { "details": "In order to maintain a healthy ecosystem engagement, the message failed to be delivered." }, "href": "https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes/" } ] } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` ## failed: recipient not in allowed list {#status-failed-not-allowed} What Meta POSTs to WhaBuzz (`fixtures/meta/status_failed_not_allowed.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB44AA=", "status": "failed", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "errors": [ { "code": 131030, "title": "Recipient phone number not in allowed list", "message": "Recipient phone number not in allowed list", "error_data": { "details": "Recipient phone number not in allowed list: Add recipient phone number to recipient list and try again." } } ] } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB44AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB44AA=:failed:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB44AA=", "status": "failed", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "errors": [ { "code": 131030, "title": "Recipient phone number not in allowed list", "message": "Recipient phone number not in allowed list", "error_data": { "details": "Recipient phone number not in allowed list: Add recipient phone number to recipient list and try again." } } ] } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` ## Three statuses in one Meta POST {#statuses-multi} What Meta POSTs to WhaBuzz (`fixtures/meta/statuses_multi.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "status": "sent", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } }, { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } }, { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB46AA=", "status": "read", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "marketing", "type": "regular" } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives (event 1 of 3, `entry[0].changes[0].value.statuses[0]`), as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=:sent:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "status": "sent", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[0]" } ``` What your endpoint receives (event 2 of 3, `entry[0].changes[0].value.statuses[1]`), as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=:delivered:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB45AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[1]" } ``` What your endpoint receives (event 3 of 3, `entry[0].changes[0].value.statuses[2]`), as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB46AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB46AA=:read:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB46AA=", "status": "read", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "marketing", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.statuses[2]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/message-error/ ======================================================================== # Message error (value-level) > Meta reported an error on the messages field with no message or status to hang it on. data.error is Meta's error object verbatim. Canonical: https://docs.whabuzz.com/events/message-error/ Meta reported an error on the messages field with no message or status to hang it on. `data.error` is Meta's error object verbatim. **Event type:** `message.error`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Error with no message attached {#value-errors} What Meta POSTs to WhaBuzz (`fixtures/meta/value_errors.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "errors": [ { "code": 131000, "title": "Something went wrong", "message": "Something went wrong", "error_data": { "details": "Message failed to send because of an unknown error." } } ] }, "field": "messages" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.error", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "err:", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "error": { "code": 131000, "title": "Something went wrong", "message": "Something went wrong", "error_data": { "details": "Message failed to send because of an unknown error." } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.errors[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/template-status/ ======================================================================== # Template status > A template changed review state. Routed by WABA. Rejections carry Meta's reason and other_info; WhaBuzz stores them as the template's status_reason and the console shows it. Canonical: https://docs.whabuzz.com/events/template-status/ A template changed review state. Routed by WABA. Rejections carry Meta's `reason` and `other_info`; WhaBuzz stores them as the template's `status_reason` and the console shows it. **Event type:** `template.status`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Approved {#template-status-approved} What Meta POSTs to WhaBuzz (`fixtures/meta/template_status_approved.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "event": "APPROVED", "message_template_id": 1689556908129832, "message_template_name": "renewal_reminder", "message_template_language": "en", "reason": "NONE", "message_template_category": "UTILITY" }, "field": "message_template_status_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "template.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "message_template_status_update:", "data": { "event": "APPROVED", "message_template_id": 1689556908129832, "message_template_name": "renewal_reminder", "message_template_language": "en", "reason": "NONE", "message_template_category": "UTILITY", "field": "message_template_status_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ## Rejected, with `reason` and `other_info` {#template-status-rejected} What Meta POSTs to WhaBuzz (`fixtures/meta/template_status_rejected.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "event": "REJECTED", "message_template_id": 1689556908129833, "message_template_name": "diwali_offer", "message_template_language": "en", "reason": "INVALID_FORMAT", "other_info": { "title": "FIRST_PAUSE", "description": "Template body contains variables at the start or end." } }, "field": "message_template_status_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "template.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "message_template_status_update:", "data": { "event": "REJECTED", "message_template_id": 1689556908129833, "message_template_name": "diwali_offer", "message_template_language": "en", "reason": "INVALID_FORMAT", "other_info": { "title": "FIRST_PAUSE", "description": "Template body contains variables at the start or end." }, "field": "message_template_status_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/template-quality/ ======================================================================== # Template quality > A template's quality score changed. Canonical: https://docs.whabuzz.com/events/template-quality/ A template's quality score changed. **Event type:** `template.quality`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## GREEN to YELLOW {#template-quality-update} What Meta POSTs to WhaBuzz (`fixtures/meta/template_quality_update.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "previous_quality_score": "GREEN", "new_quality_score": "YELLOW", "message_template_id": 1689556908129832, "message_template_name": "renewal_reminder", "message_template_language": "en" }, "field": "message_template_quality_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "template.quality", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "message_template_quality_update:", "data": { "previous_quality_score": "GREEN", "new_quality_score": "YELLOW", "message_template_id": 1689556908129832, "message_template_name": "renewal_reminder", "message_template_language": "en", "field": "message_template_quality_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/template-category/ ======================================================================== # Template category > Meta recategorised a template. Canonical: https://docs.whabuzz.com/events/template-category/ Meta recategorised a template. **Event type:** `template.category`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## UTILITY to MARKETING {#template-category-update} What Meta POSTs to WhaBuzz (`fixtures/meta/template_category_update.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "message_template_id": 1689556908129834, "message_template_name": "welcome_offer", "message_template_language": "en", "previous_category": "UTILITY", "new_category": "MARKETING", "correct_category": "MARKETING" }, "field": "template_category_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "template.category", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "template_category_update:", "data": { "message_template_id": 1689556908129834, "message_template_name": "welcome_offer", "message_template_language": "en", "previous_category": "UTILITY", "new_category": "MARKETING", "correct_category": "MARKETING", "field": "template_category_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/number-quality/ ======================================================================== # Number quality and limits > The quality rating or messaging-limit tier of a number changed. Routed by WABA and display_phone_number. Canonical: https://docs.whabuzz.com/events/number-quality/ The quality rating or messaging-limit tier of a number changed. Routed by WABA and `display_phone_number`. **Event type:** `number.quality`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## FLAGGED, tier unchanged {#phone-number-quality-update} What Meta POSTs to WhaBuzz (`fixtures/meta/phone_number_quality_update.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "display_phone_number": "14692311132", "event": "FLAGGED", "current_limit": "TIER_1K", "old_limit": "TIER_1K", "max_daily_conversation_per_phone": 1000 }, "field": "phone_number_quality_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "number.quality", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": "14692311132", "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "phone_number_quality_update:", "data": { "display_phone_number": "14692311132", "event": "FLAGGED", "current_limit": "TIER_1K", "old_limit": "TIER_1K", "max_daily_conversation_per_phone": 1000, "field": "phone_number_quality_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/number-name/ ======================================================================== # Number display name > A display-name review finished. Canonical: https://docs.whabuzz.com/events/number-name/ A display-name review finished. **Event type:** `number.name`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Display-name review decision {#phone-number-name-update} What Meta POSTs to WhaBuzz (`fixtures/meta/phone_number_name_update.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "display_phone_number": "14692311132", "decision": "APPROVED", "requested_verified_name": "WhaBuzz Demo", "rejection_reason": null }, "field": "phone_number_name_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "number.name", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": "14692311132", "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "phone_number_name_update:", "data": { "display_phone_number": "14692311132", "decision": "APPROVED", "requested_verified_name": "WhaBuzz Demo", "rejection_reason": null, "field": "phone_number_name_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/account-update/ ======================================================================== # Account update > WABA-level changes: restrictions, bans, review decisions. A restriction or ban can move your numbers out of connected; you will also get a number.connection(/events/whabuzz-events/) event. Canonical: https://docs.whabuzz.com/events/account-update/ WABA-level changes: restrictions, bans, review decisions. A restriction or ban can move your numbers out of `connected`; you will also get a [`number.connection`](https://docs.whabuzz.com/events/whabuzz-events.md) event. **Event type:** `account.update`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Account restriction {#account-update-restriction} What Meta POSTs to WhaBuzz (`fixtures/meta/account_update_restriction.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "phone_number": "14692311132", "event": "ACCOUNT_RESTRICTION", "restriction_info": [ { "restriction_type": "RESTRICTED_ADD_PHONE_NUMBER_ACTION", "expiration": 1761196323 } ] }, "field": "account_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "account.update", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "account_update:", "data": { "phone_number": "14692311132", "event": "ACCOUNT_RESTRICTION", "restriction_info": [ { "restriction_type": "RESTRICTED_ADD_PHONE_NUMBER_ACTION", "expiration": 1761196323 } ], "field": "account_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ## Account review decision {#account-update-review} What Meta POSTs to WhaBuzz (`fixtures/meta/account_update_review.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "event": "ACCOUNT_REVIEW_UPDATE", "waba_info": { "waba_id": "26059971920328384", "owner_business_id": "1234567890123456" }, "decision": "APPROVED" }, "field": "account_update" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "account.update", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": null, "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "account_update:", "data": { "event": "ACCOUNT_REVIEW_UPDATE", "waba_info": { "waba_id": "26059971920328384", "owner_business_id": "1234567890123456" }, "decision": "APPROVED", "field": "account_update" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/meta-other/ ======================================================================== # Unknown Meta fields (meta.other) > Meta adds webhook fields over time. Anything WhaBuzz has no named type for arrives as meta.other with the change value as data and the field name in data.field. Nothing is dropped, so new Meta feature Canonical: https://docs.whabuzz.com/events/meta-other/ Meta adds webhook fields over time. Anything WhaBuzz has no named type for arrives as `meta.other` with the change `value` as `data` and the field name in `data.field`. Nothing is dropped, so new Meta features reach you before WhaBuzz documents them. **Event type:** `meta.other`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## A field WhaBuzz has no type for {#unknown-field} What Meta POSTs to WhaBuzz (`fixtures/meta/unknown_field.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "value": { "anything": { "nested": [ 1, 2, { "deep": true } ] }, "display_phone_number": "14692311132" }, "field": "some_future_field" } ] } ] } ``` What your endpoint receives, as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "meta.other", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": null, "display_phone_number": "14692311132", "wamid": null, "wa_id": null, "user_id": null, "dedupe_key": "some_future_field:", "data": { "anything": { "nested": [ 1, 2, { "deep": true } ] }, "display_phone_number": "14692311132", "field": "some_future_field" }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/routing/ ======================================================================== # One Meta POST, several numbers > Meta can batch several WABAs or numbers into one POST. WhaBuzz splits it into one event per item and routes each by its own phone_number_id or WABA. An item that belongs to no tenant is stored with te Canonical: https://docs.whabuzz.com/events/routing/ Meta can batch several WABAs or numbers into one POST. WhaBuzz splits it into one event per item and routes each by its own `phone_number_id` or WABA. An item that belongs to no tenant is stored with `tenant_id: null` and never forwarded; the others are delivered normally. **Event types:** `message.inbound` and `message.status`. Fixture payloads are the WhaBuzz Demo tenant's real ids with a fictional customer number; `id`, `tenant_id` and `created_at` in envelopes are illustrative. ## Two entries: one routed number, one unknown {#multi-entry-two-numbers} What Meta POSTs to WhaBuzz (`fixtures/meta/multi_entry_two_numbers.json`): ```json { "object": "whatsapp_business_account", "entry": [ { "id": "26059971920328384", "changes": [ { "field": "messages", "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "messages": [ { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB60AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "one" } } ] } } ] }, { "id": "999999999999999", "changes": [ { "field": "messages", "value": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "15550001111", "phone_number_id": "888888888888888" }, "statuses": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB61AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } ] } } ] } ] } ``` What your endpoint receives (event 1 of 2, `entry[0].changes[0].value.messages[0]`), as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB60AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB60AA=", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "14692311132", "phone_number_id": "1013622581841046" }, "contacts": [ { "profile": { "name": "Kerry Fisher" }, "wa_id": "16505551234", "user_id": "US.13491208655302741918" } ], "message": { "from": "16505551234", "from_user_id": "US.13491208655302741918", "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB60AA=", "timestamp": "1760591523", "type": "text", "text": { "body": "one" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` What your endpoint receives (event 2 of 2, `entry[1].changes[0].value.statuses[0]`), as the body of a signed POST. `raw` is abbreviated here; on the wire it is the full body above. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "api_version": "2026-10-16", "created_at": "2025-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "999999999999999", "phone_number_id": "888888888888888", "display_phone_number": "15550001111", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB61AA=", "wa_id": "16505551234", "user_id": "US.13491208655302741918", "dedupe_key": "st:wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB61AA=:delivered:1760591523", "data": { "messaging_product": "whatsapp", "metadata": { "display_phone_number": "15550001111", "phone_number_id": "888888888888888" }, "status": { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFB61AA=", "status": "delivered", "timestamp": "1760591523", "recipient_id": "16505551234", "recipient_user_id": "US.13491208655302741918", "pricing": { "billable": true, "pricing_model": "PMP", "category": "utility", "type": "regular" } } }, "raw": { "…": "the complete Meta POST body, byte for byte, as shown above" }, "raw_path": "entry[1].changes[0].value.statuses[0]" } ``` ======================================================================== Source: https://docs.whabuzz.com/ ======================================================================== # WhaBuzz developer docs > WhaBuzz is a WhatsApp Cloud API gateway. Meta's request and response bodies, plus tenants, API keys, signed webhooks with retries and replay, and an event log. Canonical: https://docs.whabuzz.com/ WhaBuzz connects your WhatsApp Business numbers to your server through Meta's Cloud API. You send Meta's own message and template bodies to `api.whabuzz.com`; Meta's own answers come back. Everything Meta sends about your numbers reaches your server as a signed webhook, with the full original payload attached. We are a Meta Tech Provider. You pay Meta's rates to Meta. You pay WhaBuzz a flat monthly fee per number, [never per message](https://docs.whabuzz.com/pricing.md). ## The shape of it ``` your server --POST /v1/messages--> api.whabuzz.com --Graph API--> Meta your server <--signed webhook-- hooks.whabuzz.com <--webhook-- Meta ``` - **Outbound.** `POST /v1/messages` takes Meta's `/messages` body plus a `from` field. WhaBuzz adds nothing, removes nothing, and reorders nothing. The response is Meta's response. - **Inbound.** Messages, delivery statuses, template reviews, quality changes and account notices are delivered to your endpoints as events. At-least-once, signed, retried for 24 hours, replayable. - **Errors.** Either WhaBuzz stopped the request (`"source":"whabuzz"`) or Meta answered with an error, passed through untouched (`"source":"meta"`). See [Errors](https://docs.whabuzz.com/errors.md). WhaBuzz makes no decisions for you. It does not look at template categories, the 24-hour window, opt-outs or message content. Meta decides, and you see Meta's decision. ## Start here 1. [Getting started](https://docs.whabuzz.com/getting-started.md): sign up, connect a number, send a template, receive the first event. 2. [Authentication](https://docs.whabuzz.com/authentication.md): API keys, the `Authorization` header, platform keys. 3. [Webhooks](https://docs.whabuzz.com/guides/webhooks.md): signing, the verify ping, retries and replay. 4. [Event catalogue](https://docs.whabuzz.com/events.md): every payload, with the real fixture and the envelope you receive. 5. [API reference](https://docs.whabuzz.com/api.md): every endpoint with request, response and error examples. ## Pick your path - **One business, one integration.** Sign up, connect your number in the console, create a key, send. [Getting started](https://docs.whabuzz.com/getting-started.md). - **A platform serving many businesses.** Use an app key, create [tenants](https://docs.whabuzz.com/guides/tenants.md), and send your customers a hosted [Embedded Signup link](https://docs.whabuzz.com/guides/numbers.md#hosted-link). - **Moving from Plivo or WATI.** [Migration guide](https://docs.whabuzz.com/guides/migrating.md). ## For agents and scripts Every page here is also served as Markdown: add `.md` to the path, or send `Accept: text/markdown`. The whole site is in one file at [`/llms-full.txt`](https://docs.whabuzz.com/llms-full.txt), with an index at [`/llms.txt`](https://docs.whabuzz.com/llms.txt). The OpenAPI 3.1 contract is at [`/openapi.yaml`](https://docs.whabuzz.com/openapi.yaml) and [`/openapi.json`](https://docs.whabuzz.com/openapi.json). ======================================================================== Source: https://docs.whabuzz.com/getting-started/ ======================================================================== # Getting started > From sign-up to your first received webhook event in seven steps. Canonical: https://docs.whabuzz.com/getting-started/ Seven steps, in order. The console steps can also be done through the API; each step links to the endpoint. You will need: a business email address (free-mail domains are refused), a GSTIN or PAN, a WhatsApp number that is not already in use on a personal WhatsApp account, and an HTTPS URL on your server that can receive webhooks. ## 1. Sign up {#sign-up} Create an account at `app.whabuzz.com` with your business email, website and tax id (GSTIN or PAN). Confirm the email link. Your account is created in `pending_approval`. ## 2. Wait for approval {#approval} A person at WhaBuzz reviews every sign-up. Until then you can sign in and read these docs, but every `/v1` call except [`GET /v1/tenant`](https://docs.whabuzz.com/api/tenant.md#getTenant) answers `403 tenant_not_approved`. You get an email when the account is approved. If it is rejected, the email carries the reason. ## 3. Connect a number {#connect-a-number} In the console open **Numbers** and run Embedded Signup, which walks you through Meta's popup: log in with Facebook, pick or create your WhatsApp Business Account, add the number, verify it with the code Meta sends. WhaBuzz then subscribes the account to its webhooks and registers the number. Already have a WABA and a system-user token? Use [`POST /v1/numbers/connect`](https://docs.whabuzz.com/api/numbers.md#connectExisting) instead. Both paths are in [Numbers and Embedded Signup](https://docs.whabuzz.com/guides/numbers.md). The number shows `pending` until step 5 is done. A number is `connected` only after the WABA is subscribed, the number is registered, and one of your webhook endpoints has passed its verify ping. ## 4. Create an API key {#create-a-key} Console, **API keys**, or [`POST /v1/api-keys`](https://docs.whabuzz.com/api/api-keys.md#createApiKey) from a console session. The full key (`wb_live_…`) is shown once. Store it as a secret. ```bash export WHABUZZ_KEY="wb_live_7Hq2Xc9LmN4pR8sT1vW6yZ0aB3dE5fG7hJ2kM4nP6" # your key curl https://api.whabuzz.com/v1/tenant -H "Authorization: Bearer $WHABUZZ_KEY" ``` ## 5. Add a webhook endpoint {#add-a-webhook} Console, **Webhooks**, or [`POST /v1/webhooks`](https://docs.whabuzz.com/api/webhooks.md#createWebhookEndpoint). ```bash curl -X POST https://api.whabuzz.com/v1/webhooks \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{"url":"https://api.example.com/whatsapp/events","event_types":["*"]}' ``` WhaBuzz immediately POSTs a signed verify ping with a `challenge`. Your endpoint must answer `2xx` with the challenge as plain text or JSON `{"challenge":"…"}`. The response carries your signing secret (`whsec_…`), shown once. Handler code is in [Webhooks](https://docs.whabuzz.com/guides/webhooks.md#verify-ping). When the endpoint is active and the number is registered, the number turns `connected`. ## 6. Send a template {#send-a-template} To start a conversation WhatsApp requires an approved template. Create one with [`POST /v1/templates`](https://docs.whabuzz.com/api/templates.md#createTemplate) (Meta's own template body) and wait for the `template.status` event with `event: "APPROVED"`, or use a template already approved on your WABA ([`POST /v1/templates/sync`](https://docs.whabuzz.com/api/templates.md#syncTemplates) imports them). ```bash curl -X POST https://api.whabuzz.com/v1/messages \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Kerry" }, { "type": "text", "text": "31 Oct" } ] } ] } }' ``` `from` is the `phone_number_id` of one of your numbers (or its E.164 number). Everything else is Meta's body. A success answer is Meta's: ```json {"messaging_product":"whatsapp","contacts":[{"input":"16505551234","wa_id":"16505551234"}],"messages":[{"id":"wamid.HBgL…","message_status":"accepted"}]} ``` If Meta refuses, you get Meta's HTTP status and Meta's error, labelled `"source":"meta"`. While your WhatsApp Business account is in test mode, Meta answers `131030` for recipients outside the allowed list; see [Errors](https://docs.whabuzz.com/errors.md#reading-meta-errors). ## 7. Receive the first event {#first-event} Seconds later your endpoint receives a `message.status` event for the message you just sent (`sent`, then `delivered`, then `read`), and a `message.outbound` event recording the send itself. When the customer replies, you receive `message.inbound`. Verify the signature, answer `2xx` quickly, and dedupe on `dedupe_key`. The payloads are in the [event catalogue](https://docs.whabuzz.com/events.md); a status event looks like [this one](https://docs.whabuzz.com/events/message-status.md). The console's **Getting started** checklist ticks off the same four things: number connected, API key created, webhook verified, test message sent. ======================================================================== Source: https://docs.whabuzz.com/authentication/ ======================================================================== # Authentication > Bearer API keys, key rotation, platform (app) keys and the tenant header. Canonical: https://docs.whabuzz.com/authentication/ Every `/v1` call carries an API key as a Bearer token: ```bash curl https://api.whabuzz.com/v1/tenant -H "Authorization: Bearer wb_live_7Hq2Xc9LmN4pR8sT1vW6yZ0aB3dE5fG7hJ2kM4nP6" ``` Only [`GET /v1/health`](https://docs.whabuzz.com/api/health.md#getHealth) is public. ## Keys {#keys} - Format: `wb_live_` or `wb_test_` followed by 40 characters. The environment is a label that lets you keep staging credentials apart. Both hit the real WhatsApp Cloud API. - The full key is returned once, when you create or rotate it. WhaBuzz stores only a hash and the first 12 characters (`prefix`) for display. - Tenant owners and admins manage keys; agents cannot. ### Rotate {#rotate} [`POST /v1/api-keys/{key_id}/rotate`](https://docs.whabuzz.com/api/api-keys.md#rotateApiKey) creates a new key with the same name and environment and lets the old one keep working for 24 hours, so you can deploy the new key without downtime. ### Revoke {#revoke} [`DELETE /v1/api-keys/{key_id}`](https://docs.whabuzz.com/api/api-keys.md#revokeApiKey) revokes immediately. Keys are cached briefly for speed, so a revoked key usually stops working within 30 seconds, and in the worst case within about 90 seconds. ## Platform keys {#platform-keys} If you run a platform that serves many businesses (an app in WhaBuzz terms), a WhaBuzz administrator issues you an **app key**. It is not tied to one business. On tenant routes, say which business you mean with a header: ```bash curl https://api.whabuzz.com/v1/numbers \ -H "Authorization: Bearer $WHABUZZ_APP_KEY" \ -H "X-WhaBuzz-Tenant: a578246e-b97f-48e6-ae42-939ec3ccf917" ``` WhaBuzz checks that the tenant belongs to your app. Missing header on a tenant route is `400 invalid_request`. The `/v1/tenants` routes (create and list your businesses) need no header. See [Tenants](https://docs.whabuzz.com/guides/tenants.md). ## Account status gates {#status} A key works only while its tenant allows it: | Tenant status | `/v1` behaviour | |---|---| | `pending_approval`, `rejected` | `403 tenant_not_approved` on everything except `GET /v1/tenant` | | `active` | allowed | | `suspended` | `403 tenant_suspended` on everything except `GET /v1/tenant`, `GET /v1/billing*` and `GET /v1/events*`. Inbound messages are still forwarded to your endpoints. | ## Response headers {#headers} Every response carries `X-WhaBuzz-Request-Id` (quote it to support), `X-WhaBuzz-Processing-Ms` and `Server-Timing: wb;dur=, meta;dur=`. Send responses also carry `X-WhaBuzz-Event-Id`. See [Rate limits and pacing](https://docs.whabuzz.com/guides/rate-limits.md) for how to read the timing split. ======================================================================== Source: https://docs.whabuzz.com/guides/tenants/ ======================================================================== # Tenants > Your account, its status, retention setting, and how platforms create tenants for their customers. Canonical: https://docs.whabuzz.com/guides/tenants/ A **tenant** is one business account: its numbers, keys, webhook endpoints and event log. Direct customers have exactly one. Platforms using an [app key](https://docs.whabuzz.com/authentication.md#platform-keys) create one per end customer. ## Your tenant {#your-tenant} [`GET /v1/tenant`](https://docs.whabuzz.com/api/tenant.md#getTenant) returns your account, its `status`, plan, `retention_days`, and the getting-started checklist (`number_connected`, `api_key_created`, `webhook_verified`, `test_message_sent`). It works in every status, so use it as a health probe for your own credentials. [`PATCH /v1/tenant`](https://docs.whabuzz.com/api/tenant.md#updateTenant) changes the business name and `retention_days` (see [Retention](https://docs.whabuzz.com/guides/retention.md)). ## Status {#status} | Status | Meaning | |---|---| | `pending_approval` | Signed up, email confirmed, waiting for a WhaBuzz reviewer. | | `active` | Approved. Everything works. | | `rejected` | Not approved. The reason is emailed. | | `suspended` | Paused by WhaBuzz (for example, unpaid invoice past grace, or abuse). Sends stop; inbound is still forwarded. | What each status allows is in [Authentication](https://docs.whabuzz.com/authentication.md#status). ## Creating tenants for your customers {#platforms} With an app key: ```bash curl -X POST https://api.whabuzz.com/v1/tenants \ -H "Authorization: Bearer $WHABUZZ_APP_KEY" \ -H "Content-Type: application/json" \ -d '{"name":"Sunrise Clinic","external_ref":"org_4812"}' ``` See [`POST /v1/tenants`](https://docs.whabuzz.com/api/tenants.md#createTenant), [`GET /v1/tenants`](https://docs.whabuzz.com/api/tenants.md#listTenants) and [`GET /v1/tenants/{tenant_id}`](https://docs.whabuzz.com/api/tenants.md#getTenantById). Then address that business on every later call with `X-WhaBuzz-Tenant: `, and connect its number with a hosted [connect session](https://docs.whabuzz.com/guides/numbers.md#hosted-link) so your customer does Meta's popup on a WhaBuzz-hosted page. Each tenant has its own keys, webhook endpoints, event log and retention. Billing is per tenant: each tenant's connected numbers are billed on that tenant ([Pricing](https://docs.whabuzz.com/pricing.md)). ======================================================================== Source: https://docs.whabuzz.com/guides/numbers/ ======================================================================== # Numbers and Embedded Signup > Connect WhatsApp numbers with Embedded Signup, an existing WABA token, or a hosted link; connection states and what makes a number connected. Canonical: https://docs.whabuzz.com/guides/numbers/ A **number** is a WhatsApp Business phone number registered on a WhatsApp Business Account (WABA). Its id is the Meta `phone_number_id`, which you pass as `from` when sending. The resource is read with [`GET /v1/numbers`](https://docs.whabuzz.com/api/numbers.md#listNumbers) and [`GET /v1/numbers/{phone_number_id}`](https://docs.whabuzz.com/api/numbers.md#getNumber). There are three ways to connect one. All end in the same state. | You are | Use | |---|---| | A business connecting your own number, in the console | Embedded Signup in the console (it calls the first endpoint below for you) | | A developer who already has a WABA and a token | [`connect`](#connect-existing) | | A platform connecting your customers' numbers | [hosted connect session](#hosted-link) | ## Embedded Signup {#embedded-signup} Meta's Embedded Signup is a popup run in a browser. The person logs in with Facebook, picks or creates a WABA, adds a number, and verifies it by SMS or voice. When it closes, the page receives a one-time `code` and the ids of the WABA and phone number. Send those to [`POST /v1/numbers/embedded-signup`](https://docs.whabuzz.com/api/numbers.md#completeEmbeddedSignup): ```json { "code": "AQD…", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046" } ``` WhaBuzz exchanges the code for a business token, checks it (the token must belong to our Meta app, carry `whatsapp_business_management` and `whatsapp_business_messaging`, and cover this WABA), stores the token encrypted, subscribes the WABA to our webhooks, and registers the number. The token never reaches your server. ## Connect an existing WABA {#connect-existing} [`POST /v1/numbers/connect`](https://docs.whabuzz.com/api/numbers.md#connectExisting) takes the `waba_id` and either a system-user `access_token`, or an Embedded Signup `code`. WhaBuzz runs the same token checks, then connects the numbers on that WABA. ```bash curl -X POST https://api.whabuzz.com/v1/numbers/connect \ -H "Authorization: Bearer $WHABUZZ_KEY" -H "Content-Type: application/json" \ -d '{"access_token":"EAAG…","waba_id":"26059971920328384"}' ``` A token rejected by those checks answers `422 invalid_request` with the failing check in `details`. ## Hosted link for your customers {#hosted-link} Platforms should not run Meta's popup in their own app. Create a session: ```bash curl -X POST https://api.whabuzz.com/v1/connect-sessions \ -H "Authorization: Bearer $WHABUZZ_APP_KEY" -H "X-WhaBuzz-Tenant: $TENANT_ID" \ -H "Content-Type: application/json" \ -d '{"return_url":"https://yourapp.example/whatsapp/done"}' ``` The response carries `url` (`https://app.whabuzz.com/connect/`), valid for one hour. Send your customer there. After the popup, they are redirected to `return_url?session_id=…&status=connected` (or `failed`). Poll [`GET /v1/connect-sessions/{session_id}`](https://docs.whabuzz.com/api/connect-sessions.md#getConnectSession) or wait for the `number.connection` event ([WhaBuzz events](https://docs.whabuzz.com/events/whabuzz-events.md)). ## Connection state {#connection-state} A number is `connected` only when all of these hold: 1. The WABA is subscribed to WhaBuzz's webhooks. 2. The number is registered with Meta. 3. At least one of your webhook endpoints is `active` and subscribed to `message.inbound` or `*`. 4. The business token is not invalid. 5. The tenant is `active`. Otherwise the state is `pending` (never completed) or `disconnected`, and `connection_detail` says why: `waba_not_subscribed`, `not_registered`, `no_verified_endpoint`, `token_invalid` or `tenant_inactive`. Sending from a number that is not connected answers `409 number_not_connected` with that detail. Fix the detail, and the state recovers by itself; each change emits a `number.connection` event. ## Maintenance calls {#maintenance} These pass through to Meta with the number's stored token: - [`register`](https://docs.whabuzz.com/api/numbers.md#registerNumber) and [`deregister`](https://docs.whabuzz.com/api/numbers.md#deregisterNumber) - [`request-code`](https://docs.whabuzz.com/api/numbers.md#requestVerificationCode) and [`verify-code`](https://docs.whabuzz.com/api/numbers.md#verifyCode) (SMS or voice) - [`two-step`](https://docs.whabuzz.com/api/numbers.md#setTwoStepPin) sets the six-digit PIN - [`subscribe`](https://docs.whabuzz.com/api/numbers.md#resubscribeWaba) re-subscribes the WABA if the state shows `waba_not_subscribed` - [`business-profile`](https://docs.whabuzz.com/api/numbers.md#getBusinessProfile) read and [update](https://docs.whabuzz.com/api/numbers.md#updateBusinessProfile) - [`migrate`](https://docs.whabuzz.com/api/numbers.md#migrateNumber) moves a number between WABAs you control Because they are Meta calls, their errors come back as `"source":"meta"`. ======================================================================== Source: https://docs.whabuzz.com/guides/messages/ ======================================================================== # Sending messages > POST Meta's own message body plus from; bulk batches, read receipts, and what comes back. Canonical: https://docs.whabuzz.com/guides/messages/ WhaBuzz does not have its own message format. You send **Meta's `/messages` body**, with one extra field, `from`. ## Send one message {#send} [`POST /v1/messages`](https://docs.whabuzz.com/api/messages.md#sendMessage) ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "text", "text": { "body": "Your order has shipped." } } ``` - `from` (required) is the `phone_number_id` of one of your numbers, or its E.164 number. WhaBuzz removes it and calls `POST /{phone_number_id}/messages` on the Graph API. - `messaging_product` defaults to `whatsapp` if you leave it out. - Nothing else is added, removed or reordered. Every message type Meta supports works the day Meta ships it: text, template, image, video, audio, document, sticker, location, contacts, interactive, reaction, flows. - The response is Meta's, with Meta's HTTP status. WhaBuzz does not check the 24-hour window, template category, opt-out status or content. Meta decides, and if Meta refuses you see Meta's error unchanged (see [Errors](https://docs.whabuzz.com/errors.md#reading-meta-errors)). Free-form messages need an open customer service window (the customer messaged you in the last 24 hours). To start a conversation use a [template](https://docs.whabuzz.com/guides/templates.md). ## Headers you get back {#headers} `X-WhaBuzz-Request-Id` (`req_…`), `X-WhaBuzz-Event-Id` (`evt_…`, the `message.outbound` event that records this send), `X-WhaBuzz-Processing-Ms` and `Server-Timing: wb;dur=…, meta;dur=…`. ## Retry safely {#idempotency} Send an `Idempotency-Key` header. See [Idempotency](https://docs.whabuzz.com/guides/idempotency.md). ## Mark as read {#read} [`POST /v1/messages/read`](https://docs.whabuzz.com/api/messages.md#markRead) takes `from` and `message_id` (the wamid of an inbound message), and shows the customer blue ticks. Add `"typing_indicator":{"type":"text"}` to also show the typing indicator. ## Bulk sends {#batch} [`POST /v1/messages/batch`](https://docs.whabuzz.com/api/messages.md#createBatch) queues 1 to 10,000 messages in one call and answers `202` immediately: ```json { "id": "bat_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "status": "queued", "total": 3 } ``` The body is `from`, an optional `client_ref` (your reference, unique per tenant; repeating it returns the existing batch) and `messages`, an array of Meta `/messages` bodies without `from`. Items are sent in order at the number's pacing, which is Meta's messaging throughput: 20 per second for a standard number, 50 for a high-throughput one. A scheduler runs every minute and sends up to 900 items per run, so a batch of 10,000 takes about 12 minutes on a standard number. See [Rate limits and pacing](https://docs.whabuzz.com/guides/rate-limits.md). - [`GET /v1/messages/batch/{batch_id}`](https://docs.whabuzz.com/api/messages.md#getBatch): counts by status. - [`GET /v1/messages/batch/{batch_id}/items?status=failed`](https://docs.whabuzz.com/api/messages.md#listBatchItems): per-item results, each with Meta's response. - [`POST /v1/messages/batch/{batch_id}/cancel`](https://docs.whabuzz.com/api/messages.md#cancelBatch): stops items not yet sent. Meta errors on an item are recorded on that item and **never retried by WhaBuzz**, because resending a rejected message is your decision, not ours. When the batch finishes you receive a `batch.completed` event ([WhaBuzz events](https://docs.whabuzz.com/events/whabuzz-events.md)). Each item also produces its own `message.outbound` event and, later, `message.status` events. ## What happens after a send {#after} Meta's HTTP answer means "accepted", not "delivered". Delivery, read and failure arrive later as [`message.status`](https://docs.whabuzz.com/events/message-status.md) events matched on the wamid in the send response. ======================================================================== Source: https://docs.whabuzz.com/guides/media/ ======================================================================== # Media > Upload media for sending and download inbound media by id. WhaBuzz never stores your bytes. Canonical: https://docs.whabuzz.com/guides/media/ WhaBuzz never stores media. Uploads stream to Meta; downloads stream from Meta. ## Upload {#upload} [`POST /v1/media`](https://docs.whabuzz.com/api/media.md#uploadMedia) is `multipart/form-data` with `file`, `type` (the file's MIME type) and `from` (your `phone_number_id`). ```bash curl -X POST https://api.whabuzz.com/v1/media \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -F from=1013622581841046 -F type=image/jpeg -F file=@invoice.jpg # {"id":"1479537139182721"} ``` Use the id in a message: `{"type":"image","image":{"id":"1479537139182721"}}`. Meta's size and type limits apply and its errors pass through. ## Download inbound media {#download} Inbound events carry a media `id`, not bytes. [`GET /v1/media/{media_id}?from=`](https://docs.whabuzz.com/api/media.md#downloadMedia) resolves Meta's temporary URL and streams the bytes back with the right `content-type`. Fetch promptly: Meta expires media about 30 days after receipt, and WhaBuzz caches only the resolved URL (a few minutes), never the file. ## Delete {#delete} [`DELETE /v1/media/{media_id}`](https://docs.whabuzz.com/api/media.md#deleteMedia) deletes an upload from Meta. ## Template header media {#template-header} Template header images, videos and documents use a different, resumable upload that produces a **handle** (not a media id). See [`POST /v1/templates/media-handle`](https://docs.whabuzz.com/api/templates.md#createTemplateMediaHandle) and [Templates](https://docs.whabuzz.com/guides/templates.md). ======================================================================== Source: https://docs.whabuzz.com/guides/templates/ ======================================================================== # Templates > Create, edit, sync and delete WhatsApp message templates with Meta's own bodies; track review through events. Canonical: https://docs.whabuzz.com/guides/templates/ Templates are how a business starts a conversation outside the 24-hour window. WhaBuzz passes Meta's template bodies through unchanged. Templates belong to a WABA, so list and create calls take a `waba_id`. | Task | Endpoint | |---|---| | List (Meta's paging) | [`GET /v1/templates`](https://docs.whabuzz.com/api/templates.md#listTemplates) | | Read one | [`GET /v1/templates/{template_id}`](https://docs.whabuzz.com/api/templates.md#getTemplate) | | Create | [`POST /v1/templates`](https://docs.whabuzz.com/api/templates.md#createTemplate) | | Edit | [`POST /v1/templates/{template_id}`](https://docs.whabuzz.com/api/templates.md#editTemplate) | | Delete | [`DELETE /v1/templates/{template_id}`](https://docs.whabuzz.com/api/templates.md#deleteTemplate) | | Import everything already on the WABA | [`POST /v1/templates/sync`](https://docs.whabuzz.com/api/templates.md#syncTemplates) | | Meta's template library | [`GET /v1/templates/library`](https://docs.whabuzz.com/api/templates.md#listTemplateLibrary) | | Upload header media (get a handle) | [`POST /v1/templates/media-handle`](https://docs.whabuzz.com/api/templates.md#createTemplateMediaHandle) | ## Create {#create} ```bash curl -X POST https://api.whabuzz.com/v1/templates \ -H "Authorization: Bearer $WHABUZZ_KEY" -H "Content-Type: application/json" \ -d '{ "waba_id": "26059971920328384", "name": "renewal_reminder", "language": "en", "category": "UTILITY", "components": [ { "type": "BODY", "text": "Hi {{1}}, your plan renews on {{2}}.", "example": { "body_text": [["Kerry", "31 Oct"]] } } ] }' ``` Meta answers with the template id, status (usually `PENDING`) and category. ## Review and status {#review} Meta reviews templates asynchronously. You hear about the result as a [`template.status`](https://docs.whabuzz.com/events/template-status.md) event: `APPROVED`, `REJECTED` (with Meta's reason), `PAUSED`, `DISABLED`. Also watch [`template.quality`](https://docs.whabuzz.com/events/template-quality.md) and [`template.category`](https://docs.whabuzz.com/events/template-category.md): Meta can re-categorise a template, which changes what each send costs you at Meta. Rejection reasons are also kept in `status_reason` when you list or sync. ## Sync {#sync} [`POST /v1/templates/sync`](https://docs.whabuzz.com/api/templates.md#syncTemplates) walks the WABA's templates page by page and stores a local copy, so you can list them without hitting Meta each time. Call it once after connecting an existing WABA, and again if you create templates in Meta's own manager. ## Sending {#sending} See [Sending messages](https://docs.whabuzz.com/guides/messages.md) and the template example in [Getting started](https://docs.whabuzz.com/getting-started.md#send-a-template). A template send that Meta rejects (wrong parameter count, unapproved template, paused template) answers with Meta's error and `"source":"meta"`. ======================================================================== Source: https://docs.whabuzz.com/guides/webhooks/ ======================================================================== # Webhooks > Endpoints, signed deliveries, the verify ping, retries, replay and deduplication. Canonical: https://docs.whabuzz.com/guides/webhooks/ Everything Meta tells WhaBuzz about your numbers, plus a few events WhaBuzz raises itself, is delivered to your **webhook endpoints** as signed HTTP POSTs. One event per request. The [event catalogue](https://docs.whabuzz.com/events.md) shows every payload. ## Delivery guarantees {#guarantees} - **At least once.** Treat every event as possibly repeated. Dedupe on `dedupe_key`. - **Not ordered.** A `read` status can arrive before `delivered`. Compare timestamps. - **Retried for 24 hours** on failure (see [Retries](#retries)), then marked `dead`. Dead deliveries can be [replayed](#replay) within your retention window. - **Full fidelity.** The `raw` field holds Meta's exact original POST body. ## Endpoints {#endpoints} [`POST /v1/webhooks`](https://docs.whabuzz.com/api/webhooks.md#createWebhookEndpoint) creates one. Up to 10 per tenant. ```json { "url": "https://api.example.com/whatsapp/events", "event_types": ["*"], "description": "prod" } ``` - `url` must be `https`, a hostname (not an IP address), and not under `whabuzz.com`. - `event_types` is `["*"]` for everything, or an exact list such as `["message.inbound","message.status"]`. - `status` is `pending_verification`, then `active` after the [verify ping](#verify-ping), or `disabled` (paused by you). - The create response includes the **signing secret**, `whsec_` plus 32 random bytes, base64url. It is shown once. Rotate with [`rotate-secret`](https://docs.whabuzz.com/api/webhooks.md#rotateWebhookSecret) (both secrets sign for an overlap of `overlap_hours`, 0 to 168, default 24). Signing keys are cached for speed, so for up to about 90 seconds after a rotation some deliveries still carry only the old signature: keep accepting the old secret for at least that long, even with `overlap_hours: 0`. Manage with [list](https://docs.whabuzz.com/api/webhooks.md#listWebhookEndpoints), [get](https://docs.whabuzz.com/api/webhooks.md#getWebhookEndpoint), [update](https://docs.whabuzz.com/api/webhooks.md#updateWebhookEndpoint) and [delete](https://docs.whabuzz.com/api/webhooks.md#deleteWebhookEndpoint). ## Verify ping {#verify-ping} Right after creation (and whenever you call [`POST /v1/webhooks/{endpoint_id}/verify`](https://docs.whabuzz.com/api/webhooks.md#verifyWebhookEndpoint)) WhaBuzz POSTs: ```json { "type": "webhook.verify", "challenge": "6f1c0b8e4a7d4f29b3e5a0c2d9f81a47", "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "created_at": "2026-10-16T09:30:00.000Z" } ``` Answer `2xx` within 5 seconds with the challenge echoed, either as the plain-text body or as JSON `{"challenge":"…"}`. Anything else leaves the endpoint in `pending_verification` and the API call answers `422 webhook_verify_failed` with `details.http_status` and a `body_excerpt` of what your server returned. The endpoint is still created, so the same response includes its signing secret in `details.secret`; fix your handler and call `verify` again. The ping is signed like every delivery. ## Signature {#signature} Each request carries: ``` X-WhaBuzz-Signature: t=1760591523,v1=5b0c…e1 ``` `v1` is the lowercase hex HMAC-SHA256, keyed with your signing secret, of the string `{t}.{raw request body}`. During a secret rotation the header carries two `v1=` values; accept the request if **any** matches. Reject if `t` is more than 300 seconds from your clock. Compute over the raw bytes, before any JSON parsing. ### Node.js {#verify-node} ```js import crypto from 'node:crypto'; export function verify(rawBody, header, secret) { const parts = Object.fromEntries(header.split(',').map((p) => p.split(/=(.*)/s).slice(0, 2))); const t = Number(parts.t); if (!t || Math.abs(Date.now() / 1000 - t) > 300) return false; const expected = crypto.createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return header.split(',').filter((p) => p.startsWith('v1=')).some((p) => { const got = Buffer.from(p.slice(3), 'hex'); const want = Buffer.from(expected, 'hex'); return got.length === want.length && crypto.timingSafeEqual(got, want); }); } ``` ### Python {#verify-python} ```python import hashlib, hmac, time def verify(raw_body: bytes, header: str, secret: str) -> bool: parts = [p.split("=", 1) for p in header.split(",")] t = int(next(v for k, v in parts if k == "t")) if abs(time.time() - t) > 300: return False expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest() return any(hmac.compare_digest(v, expected) for k, v in parts if k == "v1") ``` ### PHP {#verify-php} ```php function verify(string $rawBody, string $header, string $secret): bool { $t = null; $sigs = []; foreach (explode(',', $header) as $p) { [$k, $v] = explode('=', $p, 2); if ($k === 't') $t = (int)$v; if ($k === 'v1') $sigs[] = $v; } if (!$t || abs(time() - $t) > 300) return false; $expected = hash_hmac('sha256', $t . '.' . $rawBody, $secret); foreach ($sigs as $s) if (hash_equals($expected, $s)) return true; return false; } ``` ## Request headers {#headers} | Header | Value | |---|---| | `X-WhaBuzz-Signature` | `t=,v1=[,v1=]` | | `X-WhaBuzz-Event-Id` | `evt_…`, same as the body `id` | | `X-WhaBuzz-Event-Type` | for example `message.inbound` | | `X-WhaBuzz-Delivery-Id` | `dlv_…`, one per attempt chain | | `X-WhaBuzz-Attempt` | 1, 2, 3 … | | `X-WhaBuzz-Received-At` | when WhaBuzz received the event from Meta | | `X-WhaBuzz-Processing-Ms` | time WhaBuzz spent before forwarding | | `User-Agent` | `WhaBuzz-Webhooks/1` | ## Retries {#retries} The first attempt is made immediately, inline, with a 3-second deadline. A delivery succeeds on any `2xx`. Redirects are not followed. Retry attempts time out at 10 seconds. Anything else (non-2xx, timeout, connection error) is a failure and is retried at: 30 seconds, 1 minute, 2, 5, 10, 20, 40 minutes, 1 hour, then hourly, until 24 hours after the first attempt. After that the delivery is `dead`. Retries are driven by a per-minute scheduler, so the practical minimum gap is the next minute tick. After 5 consecutive failures an endpoint is flagged and new events skip the immediate attempt and wait for the scheduler, which protects both sides during an outage. Return `2xx` as soon as you have durably queued the event; do the work afterwards. Inspect attempts with [`GET /v1/webhook-deliveries`](https://docs.whabuzz.com/api/webhooks.md#listDeliveries) and [`GET /v1/webhook-deliveries/{delivery_id}`](https://docs.whabuzz.com/api/webhooks.md#getDelivery). ## Replay {#replay} - One delivery: [`POST /v1/webhook-deliveries/{delivery_id}/replay`](https://docs.whabuzz.com/api/webhooks.md#replayDelivery) makes one synchronous attempt and returns its result. It creates a new delivery with `is_replay: true`. - Many: [`POST /v1/webhooks/{endpoint_id}/replay`](https://docs.whabuzz.com/api/webhooks.md#bulkReplay) with a filter, answers `202 {"queued": n}`, capped at 10,000. ```json { "from": "2026-10-16T00:00:00Z", "to": "2026-10-16T06:00:00Z", "status": ["dead","failed"], "event_types": ["message.inbound"] } ``` Replay works while the event's payload is inside your [retention](https://docs.whabuzz.com/guides/retention.md) window. Beyond it the call answers `404 not_found` with `details.reason: "payload_expired"`. ## Deduplicate {#dedupe} Every event has a `dedupe_key` that is identical across retries and replays of the same fact: | Event | `dedupe_key` | |---|---| | `message.inbound` | `msg:{wamid}` | | `message.status` | `st:{wamid}:{status}:{timestamp}` | | `message.error` | `err:{sha256 of the error object}` | | Other Meta fields | `{field}:{sha256 of the canonical value}` | | `message.outbound` | `out:{event_id}` | Keep keys you have processed for at least 24 hours (the retry horizon), longer if you replay. ======================================================================== Source: https://docs.whabuzz.com/guides/idempotency/ ======================================================================== # Idempotency > Retry a send without double-sending, using the Idempotency-Key header. Canonical: https://docs.whabuzz.com/guides/idempotency/ Networks fail between "we sent it" and "you heard back". Add an `Idempotency-Key` header to [`POST /v1/messages`](https://docs.whabuzz.com/api/messages.md#sendMessage) (up to 255 characters, any string you generate, a UUID works) and a retry will not send twice. ```bash curl -X POST https://api.whabuzz.com/v1/messages \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Idempotency-Key: order-48213-shipped" \ -H "Content-Type: application/json" -d @body.json ``` | Situation | Result | |---|---| | First request with the key | Processed normally. The answer is stored for 24 hours. | | Same key, same body, original finished | The stored answer is replayed with the header `Idempotent-Replayed: true`. Nothing is sent to Meta. | | Same key, original still running | `409 idempotency_conflict`. Wait and retry. | | Same key, different body | `422 idempotency_conflict`. Use a new key. | Do not fire two requests with the same key at the same time. If WhaBuzz could not reach Meta (`502 meta_unreachable`) the outcome is unknown. That 502 is stored against the key too, so a retry returns the same 502 instead of risking a duplicate. Use a new key only after you have checked, through [`GET /v1/events`](https://docs.whabuzz.com/api/events.md#listEvents) or a `message.status` event, that the first message was not sent. Batches use `client_ref` for the same purpose; see [Sending messages](https://docs.whabuzz.com/guides/messages.md#batch). ======================================================================== Source: https://docs.whabuzz.com/guides/rate-limits/ ======================================================================== # Rate limits and pacing > WhaBuzz does not rate limit the API in v1; Meta's limits pass through. How to pace sends and read timing headers. Canonical: https://docs.whabuzz.com/guides/rate-limits/ ## WhaBuzz does not throttle your API calls {#no-limit} There is no WhaBuzz request quota on `/v1` in v1. The only WhaBuzz rate limit is on sign-up, login and password-reset in the console (`429 rate_limited` with `Retry-After`). ## Meta's limits pass through {#meta} Meta limits you, and its errors reach you unchanged with `"source":"meta"`. The ones you will meet: | Meta code | Meaning | What to do | |---|---|---| | `130429` | Throughput limit reached (messages per second per number) | Back off and retry later. Pace sends. | | `131056` | Too many messages to the same recipient in a short time | Wait before sending that customer again. | | `131048`, `131049` | Spam rate or marketing frequency limits | Do not retry the same message; review content and audience. | A messaging tier (how many unique customers you may start conversations with per day) applies to each number and is reported in [`number.quality`](https://docs.whabuzz.com/events/number-quality.md) events. The full list is on [Meta's error page](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes). ## Pacing bulk sends {#pacing} Use [batches](https://docs.whabuzz.com/guides/messages.md#batch) and let WhaBuzz pace for you: 20 messages per second per standard number, 50 for a high-throughput number. A scheduler runs every minute and sends at most 900 items per run, so plan on about 900 messages per minute per run. Failed items are not retried; list them with `?status=failed` and resend what you choose. If you send one at a time instead, keep to the same ceiling and treat `130429` as a signal to slow down. ## Reading latency {#timing} Every response carries `Server-Timing: wb;dur=12, meta;dur=184` and `X-WhaBuzz-Processing-Ms`. `wb` is time spent in WhaBuzz; `meta` is time waiting on Meta's Graph API. WhaBuzz gives Meta 15 seconds, then answers `502 meta_unreachable` (outcome unknown; see [Idempotency](https://docs.whabuzz.com/guides/idempotency.md)). ======================================================================== Source: https://docs.whabuzz.com/guides/retention/ ======================================================================== # Retention > What WhaBuzz stores, for how long, and how retention controls the replay window. Canonical: https://docs.whabuzz.com/guides/retention/ ## What is kept {#kept} | Data | How long | |---|---| | Event metadata (id, type, timestamps, wamid, wa_id, number) | Forever | | Event bodies and the `raw` Meta payload | Your `retention_days`, then removed | | Webhook delivery records and attempts | 13 months | | Media bytes | Never stored. Streamed through. | | Business access tokens | Until you disconnect the number; stored encrypted | ## Your setting {#setting} `retention_days` is one of **30, 90, 180 or 365**, default **90**. Change it with [`PATCH /v1/tenant`](https://docs.whabuzz.com/api/tenant.md#updateTenant). A shorter value removes older bodies at the next cleanup; a longer one only applies to events from now on. Under the hood events live in monthly partitions that are dropped at 13 months. ## Replay window {#replay} An event can be replayed only while its body exists, so the replay window equals your retention. Replaying older events answers `404 not_found` with `details.reason: "payload_expired"`. See [Webhooks](https://docs.whabuzz.com/guides/webhooks.md#replay). Read the log yourself with [`GET /v1/events`](https://docs.whabuzz.com/api/events.md#listEvents) and [`GET /v1/events/{event_id}`](https://docs.whabuzz.com/api/events.md#getEvent). ## Customer data {#customer} Message bodies contain your customers' personal data. Choose the shortest retention that serves you, and mirror what you need into your own system from the webhook. ======================================================================== Source: https://docs.whabuzz.com/guides/migrating/ ======================================================================== # Migrating from Plivo or WATI > Move your numbers, templates and integration from another WhatsApp provider onto WhaBuzz. Canonical: https://docs.whabuzz.com/guides/migrating/ WhaBuzz speaks Meta's Cloud API. If your current provider (Plivo, WATI, or any BSP) wraps that API in its own format, migration is mostly **changing what you send**, not **where your customers' conversations live**. ## What carries over {#carries} - **Your WhatsApp Business Account and its numbers**, if the account is yours. WhaBuzz connects to the WABA, not to a provider. - **Approved templates**, by name and language. [Sync](https://docs.whabuzz.com/guides/templates.md#sync) imports them after you connect. - **Quality rating, messaging tier and display name**, which belong to the number at Meta. ## What does not {#not} - Provider-specific features: campaign builders, chatbot flows, inboxes, contact lists, opt-in tracking. WhaBuzz is an API. Keep contact and opt-out state in your own system. - Provider message ids. Message history stays with your old provider; WhaBuzz starts its log on connection. - Your provider's request and webhook formats. You will change both. ## Steps {#steps} 1. **Check who owns the WABA.** In Meta Business Manager, open WhatsApp accounts. If the WABA belongs to your business, you can connect it yourself. If it is owned by the provider, ask them to transfer it to your business, or migrate the number to a WABA you own using Meta's number migration. 2. **Connect it.** Use [Embedded Signup](https://docs.whabuzz.com/guides/numbers.md#embedded-signup) in the console, or [`POST /v1/numbers/connect`](https://docs.whabuzz.com/api/numbers.md#connectExisting) with a system-user token. Moving a number from a different provider's WABA to yours is [`POST /v1/numbers/migrate`](https://docs.whabuzz.com/api/numbers.md#migrateNumber). 3. **Import templates.** [`POST /v1/templates/sync`](https://docs.whabuzz.com/api/templates.md#syncTemplates). 4. **Add a webhook endpoint** and verify it ([Webhooks](https://docs.whabuzz.com/guides/webhooks.md)). Keep your old provider's webhook receiving until you cut over. 5. **Change your send code.** Meta's body replaces your provider's. See the mapping below. 6. **Change your inbound handler.** The `data` field of a WhaBuzz event holds Meta's change value and `raw` holds Meta's full POST. If your code already parsed Meta's format, the field paths are Meta's. Add signature verification and `dedupe_key`. 7. **Cut over.** WhatsApp delivers inbound messages to one webhook subscription per app at a time. Subscribing the WABA to WhaBuzz moves inbound delivery. Do it at a quiet hour, send a test message to the number, and confirm a `message.inbound` event arrives. Cutting a number over has a short window where inbound messages go to neither provider. Keep the old provider's account open until you have seen traffic arrive on WhaBuzz. ## Mapping a send {#mapping} Whatever your old call looked like (provider JSON with the destination, template name and variables), the WhaBuzz equivalent is Meta's body: ```json { "from": "1013622581841046", "to": "16505551234", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [{ "type": "body", "parameters": [{ "type": "text", "text": "Kerry" }] }] } } ``` Meta's [message reference](https://developers.facebook.com/docs/whatsapp/cloud-api/reference/messages) documents every field. If your old provider flattened variables into a list, you will build `components[].parameters[]` yourself. ## Things that will differ {#differ} - **Errors** are Meta's, not a provider's translated codes. See [Errors](https://docs.whabuzz.com/errors.md). - **Statuses** arrive as Meta's `sent`, `delivered`, `read`, `failed`, one event each, unordered. - **Opt-outs.** WhaBuzz does not manage opt-outs. If a customer sends "STOP", you receive it as a `message.inbound` and you decide. - **Pricing.** You pay Meta's per-conversation or per-message rates directly to Meta; WhaBuzz charges a [flat monthly fee per number](https://docs.whabuzz.com/pricing.md). ======================================================================== Source: https://docs.whabuzz.com/api/ ======================================================================== # API reference > Base URL, conventions and an index of every endpoint group. Canonical: https://docs.whabuzz.com/api/ Base URL: `https://api.whabuzz.com`. All bodies are JSON unless stated. The contract is generated from the [OpenAPI 3.1 file](https://docs.whabuzz.com/openapi.yaml) ([JSON](https://docs.whabuzz.com/openapi.json)); these pages are generated from the same file, so they cannot drift. ## Conventions {#conventions} - **Auth.** `Authorization: Bearer `. See [Authentication](https://docs.whabuzz.com/authentication.md). Platform keys add `X-WhaBuzz-Tenant`. - **Meta bodies are Meta's.** Message, template and media endpoints take and return Meta's shapes; the reference shows examples and links to Meta for the full field list. - **Errors.** `{"source":"whabuzz"|"meta", …}`. See [Errors](https://docs.whabuzz.com/errors.md). - **Ids.** `req_` request, `evt_` event, `dlv_` delivery, `bat_` batch; others are UUIDs or Meta's ids. - **Timing.** Every response has `Server-Timing` and `X-WhaBuzz-Processing-Ms`. - **Version.** `2026-10-16`. ## Endpoint groups {#groups} - [Health](https://docs.whabuzz.com/api/health.md): unauthenticated liveness. - [Tenant (your account)](https://docs.whabuzz.com/api/tenant.md) and [Tenants](https://docs.whabuzz.com/api/tenants.md) for platforms. - [API keys](https://docs.whabuzz.com/api/api-keys.md) - [Numbers](https://docs.whabuzz.com/api/numbers.md) and [Connect sessions](https://docs.whabuzz.com/api/connect-sessions.md) - [Messages](https://docs.whabuzz.com/api/messages.md), including batches - [Media](https://docs.whabuzz.com/api/media.md) - [Templates](https://docs.whabuzz.com/api/templates.md) - [Webhooks](https://docs.whabuzz.com/api/webhooks.md) and deliveries - [Event log](https://docs.whabuzz.com/api/events.md) - [Billing](https://docs.whabuzz.com/api/billing.md) - [Admin](https://docs.whabuzz.com/api/admin.md): WhaBuzz staff only; documented for completeness. ======================================================================== Source: https://docs.whabuzz.com/api/health/ ======================================================================== # Health > Liveness and database reachability. Canonical: https://docs.whabuzz.com/api/health/ Liveness and database reachability. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/health`](#getHealth): Service health ## Service health {#getHealth} `GET /v1/health` **Auth:** None (public). **Operation id:** `getHealth`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/health" ``` **Responses** **200** Healthy ```json { "ok": true, "sha": "a77affe", "db": "ok" } ``` **503** Database unreachable ```json { "ok": false, "sha": "a77affe", "db": "error" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/tenant/ ======================================================================== # Tenant (your account) > The tenant your key belongs to. Canonical: https://docs.whabuzz.com/api/tenant/ The tenant your key belongs to. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/tenant`](#getTenant): Current tenant, including the Getting-started checklist - [`PATCH /v1/tenant`](#updateTenant): Update retention or billing email ## Current tenant, including the Getting-started checklist {#getTenant} `GET /v1/tenant` Allowed for every tenant status, so a pending tenant can see why it is blocked. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getTenant`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/tenant" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Tenant ```json { "id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "name": "Acme Fitness", "status": "active", "sandbox": false, "retention_days": 90, "billing_status": "trialing", "trial_ends_at": "2026-10-30T09:00:00Z", "created_at": "2026-10-16T09:00:00Z", "checklist": { "number_connected": true, "api_key_created": true, "webhook_verified": false, "test_message_sent": false } } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 401 | `unauthorized` | Missing or invalid credentials | ## Update retention or billing email {#updateTenant} `PATCH /v1/tenant` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `updateTenant`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `retention_days` | `30` or `90` or `180` or `365` | no | | | `billing_email` | string (email) | no | | | `name` | string | no | | Request example: ```json { "retention_days": 180 } ``` cURL: ```bash curl -X PATCH "https://api.whabuzz.com/v1/tenant" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "retention_days": 180 }' ``` **Responses** **200** Updated tenant ```json { "id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "name": "Acme Fitness", "status": "active", "retention_days": 180 } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `invalid_request` | Invalid request | | 403 | `forbidden` | Not allowed for this caller | ======================================================================== Source: https://docs.whabuzz.com/api/tenants/ ======================================================================== # Tenants > Platform (app) keys only. Create and list the businesses you manage. Canonical: https://docs.whabuzz.com/api/tenants/ Platform (app) keys only. Create and list the businesses you manage. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/tenants`](#listTenants): List tenants created by your app key - [`POST /v1/tenants`](#createTenant): Create a tenant for one of your customers - [`GET /v1/tenants/{tenant_id}`](#getTenantById): Get one of your app's tenants ## List tenants created by your app key {#listTenants} `GET /v1/tenants` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listTenants`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | | `external_ref` | query | string | no | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/tenants" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Tenants ```json { "data": [ { "id": "7d0f3c1e-2b8a-4c55-9f61-0e9b1a2c3d4e", "name": "Sunrise Clinic", "external_ref": "org_4812", "status": "active", "created_at": "2026-10-16T10:00:00Z" } ], "next_cursor": null } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 403 | `forbidden` | Not allowed for this caller | ## Create a tenant for one of your customers {#createTenant} `POST /v1/tenants` Tenants created with an app key are active immediately. Connect their number with a Connect session. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createTenant`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `name` | string | yes | | | `external_ref` | string | no | Your own id for this business. Unique per app. | | `retention_days` | `30` or `90` or `180` or `365` | no | Default `90`. | Request example: ```json { "name": "Sunrise Clinic", "external_ref": "org_4812" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/tenants" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Sunrise Clinic", "external_ref": "org_4812" }' ``` **Responses** **201** Created ```json { "id": "7d0f3c1e-2b8a-4c55-9f61-0e9b1a2c3d4e", "name": "Sunrise Clinic", "external_ref": "org_4812", "status": "active", "retention_days": 90, "created_at": "2026-10-16T10:00:00Z" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `invalid_request` | Invalid request | | 403 | `forbidden` | Not allowed for this caller | ## Get one of your app's tenants {#getTenantById} `GET /v1/tenants/{tenant_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getTenantById`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | path | string (uuid) | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/tenants/$TENANT_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Tenant ```json { "id": "7d0f3c1e-2b8a-4c55-9f61-0e9b1a2c3d4e", "name": "Sunrise Clinic", "external_ref": "org_4812", "status": "active" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 404 | `not_found` | Not found | ======================================================================== Source: https://docs.whabuzz.com/api/api-keys/ ======================================================================== # API keys > Tenant API keys. The full key is shown once. Canonical: https://docs.whabuzz.com/api/api-keys/ Tenant API keys. The full key is shown once. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/api-keys`](#listApiKeys): List API keys (prefix only) - [`POST /v1/api-keys`](#createApiKey): Create an API key - [`DELETE /v1/api-keys/{key_id}`](#revokeApiKey): Revoke a key now - [`POST /v1/api-keys/{key_id}/rotate`](#rotateApiKey): Rotate a key ## List API keys (prefix only) {#listApiKeys} `GET /v1/api-keys` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listApiKeys`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/api-keys" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Keys ```json { "data": [ { "id": "0b9f8e7d-6c5b-4a39-8271-605f4e3d2c1b", "name": "Production", "environment": "live", "prefix": "wb_live_7Hq2", "created_at": "2026-10-16T09:10:00Z", "last_used_at": "2026-10-16T09:40:00Z", "expires_at": null, "revoked_at": null } ] } ``` ## Create an API key {#createApiKey} `POST /v1/api-keys` The full key is in this response only. Store it now. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createApiKey`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `name` | string | yes | | | `environment` | `live` or `test` | no | Default `"live"`. | Request example: ```json { "name": "Production", "environment": "live" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/api-keys" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Production", "environment": "live" }' ``` **Responses** **201** Created ```json { "id": "0b9f8e7d-6c5b-4a39-8271-605f4e3d2c1b", "name": "Production", "environment": "live", "prefix": "wb_live_7Hq2", "key": "wb_live_7Hq2Xc9LmN4pR8sT1vW6yZ0aB3dE5fG7hJ2kM4nP6", "created_at": "2026-10-16T09:10:00Z" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 403 | `forbidden` | Not allowed for this caller | ## Revoke a key now {#revokeApiKey} `DELETE /v1/api-keys/{key_id}` Takes effect within 30 seconds everywhere. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `revokeApiKey`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | string (uuid) | yes | | cURL: ```bash curl -X DELETE "https://api.whabuzz.com/v1/api-keys/$KEY_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Revoked ```json { "id": "0b9f8e7d-6c5b-4a39-8271-605f4e3d2c1b", "revoked_at": "2026-10-16T11:00:00Z" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 404 | `not_found` | Not found | ## Rotate a key {#rotateApiKey} `POST /v1/api-keys/{key_id}/rotate` Returns a new key. The old key keeps working for 24 hours, then expires. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `rotateApiKey`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `key_id` | path | string (uuid) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/api-keys/$KEY_ID/rotate" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **201** New key ```json { "id": "5e4d3c2b-1a09-4f8e-9d7c-6b5a49382716", "name": "Production", "environment": "live", "prefix": "wb_live_Qm3x", "key": "wb_live_Qm3xV8bN1cK5zL7aS2dF4gH6jP9rT0wY3uE5iO7", "replaces": "0b9f8e7d-6c5b-4a39-8271-605f4e3d2c1b", "old_key_expires_at": "2026-10-17T11:00:00Z" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/numbers/ ======================================================================== # Numbers > Connect and manage WhatsApp Business numbers. A number is connected only after the WABA is subscribed to WhaBuzz, the number is registered, and a webhook endpoint has passed its verify ping. Canonical: https://docs.whabuzz.com/api/numbers/ Connect and manage WhatsApp Business numbers. A number is `connected` only after the WABA is subscribed to WhaBuzz, the number is registered, and a webhook endpoint has passed its verify ping. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/numbers`](#listNumbers): List numbers - [`GET /v1/numbers/{phone_number_id}`](#getNumber): Get a number - [`POST /v1/numbers/embedded-signup`](#completeEmbeddedSignup): Finish Embedded Signup with the code from Meta's popup - [`POST /v1/numbers/connect`](#connectExisting): Connect an existing WABA with a business system-user token - [`POST /v1/numbers/migrate`](#migrateNumber): Start migrating a number into one of your WABAs - [`POST /v1/numbers/{phone_number_id}/register`](#registerNumber): Register the number with Cloud API - [`POST /v1/numbers/{phone_number_id}/deregister`](#deregisterNumber): Deregister the number - [`POST /v1/numbers/{phone_number_id}/request-code`](#requestVerificationCode): Request an SMS or voice verification code - [`POST /v1/numbers/{phone_number_id}/verify-code`](#verifyCode): Verify the code - [`POST /v1/numbers/{phone_number_id}/two-step`](#setTwoStepPin): Set or change the two-step verification PIN - [`POST /v1/numbers/{phone_number_id}/subscribe`](#resubscribeWaba): Re-subscribe the number's WABA to WhaBuzz (repair) - [`GET /v1/numbers/{phone_number_id}/business-profile`](#getBusinessProfile): Get the WhatsApp business profile - [`POST /v1/numbers/{phone_number_id}/business-profile`](#updateBusinessProfile): Update the WhatsApp business profile ## List numbers {#listNumbers} `GET /v1/numbers` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listNumbers`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/numbers" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Numbers ```json { "data": [ { "phone_number_id": "1013622581841046", "display_phone_number": "+1 469-231-1132", "verified_name": "WhaBuzz Demo", "waba_id": "26059971920328384", "connection_state": "connected", "connection_detail": null, "quality_rating": "GREEN", "messaging_limit_tier": "TIER_250", "throughput_level": "STANDARD" } ] } ``` ## Get a number {#getNumber} `GET /v1/numbers/{phone_number_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getNumber`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | | `refresh` | query | boolean | no | Re-read the number from Meta first (stored as `meta_snapshot`). | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Number connected: ```json { "phone_number_id": "1013622581841046", "display_phone_number": "+1 469-231-1132", "verified_name": "WhaBuzz Demo", "waba_id": "26059971920328384", "connection_state": "connected", "connection_detail": null, "quality_rating": "GREEN", "messaging_limit_tier": "TIER_250", "throughput_level": "STANDARD", "name_status": "APPROVED", "registered_at": "2026-10-02T06:00:00Z", "last_event_at": "2026-10-16T05:12:03Z" } ``` pending: ```json { "phone_number_id": "1013622581841046", "display_phone_number": "+1 469-231-1132", "waba_id": "26059971920328384", "connection_state": "pending", "connection_detail": "no_verified_endpoint" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 404 | `not_found` | Not found | ## Finish Embedded Signup with the code from Meta's popup {#completeEmbeddedSignup} `POST /v1/numbers/embedded-signup` Exchanges the code, checks the token, subscribes the WABA to WhaBuzz, registers the number and stores Meta's view of it. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `completeEmbeddedSignup`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `code` | string | yes | | | `waba_id` | string | yes | | | `phone_number_id` | string | yes | | | `pin` | string | no | Two-step PIN to register with. Generated when omitted. Pattern `^[0-9]{6}$`. | Request example: ```json { "code": "AQBx…", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/embedded-signup" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "AQBx…", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046" }' ``` **Responses** **200** Number stored. `connection_state` tells you what is left. ```json { "phone_number_id": "1013622581841046", "display_phone_number": "+1 469-231-1132", "waba_id": "26059971920328384", "connection_state": "pending", "connection_detail": "no_verified_endpoint" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Connect an existing WABA with a business system-user token {#connectExisting} `POST /v1/numbers/connect` For businesses that already have a WABA. The token must belong to WhaBuzz's Meta app (`debug_token` app id), carry `whatsapp_business_management` and `whatsapp_business_messaging`, and list `waba_id` in its granular scopes. WhaBuzz subscribes the WABA and imports its numbers. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `connectExisting`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `waba_id` | string | yes | | | `access_token` | string | no | | | `code` | string | no | Alternative to access_token: an Embedded Signup code. | Request example: ```json { "waba_id": "1496378315413646", "access_token": "EAAG…" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/connect" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "waba_id": "1496378315413646", "access_token": "EAAG…" }' ``` **Responses** **200** Imported numbers ```json { "waba_id": "1496378315413646", "numbers": [ { "phone_number_id": "301234567890123", "display_phone_number": "+91 95158 47444", "connection_state": "pending", "connection_detail": "not_registered" } ] } ``` **400** Token checks failed, or Meta error whabuzz: ```json { "source": "whabuzz", "error": { "code": "invalid_request", "message": "Token is not scoped to WABA 1496378315413646", "details": { "granular_scopes": [ "whatsapp_business_messaging" ] } }, "request_id": "req_01JAB3M0P4Q7R2S5T8V1W4X7Y0" } ``` Meta 190 passed through (HTTP 401 from Meta becomes 401 here): ```json { "source": "meta", "error": { "message": "Error validating access token: Session has expired.", "type": "OAuthException", "code": 190, "error_subcode": 463, "fbtrace_id": "C3d4E5f6G7h8I9j0" } } ``` ## Start migrating a number into one of your WABAs {#migrateNumber} `POST /v1/numbers/migrate` Wraps `POST /{waba_id}/phone_numbers` with `migrate_phone_number=true`. Follow with request-code, verify-code and register. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `migrateNumber`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `waba_id` | string | yes | | | `cc` | string | yes | | | `phone_number` | string | yes | | Request example: ```json { "waba_id": "1496378315413646", "cc": "91", "phone_number": "9515847444" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/migrate" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "waba_id": "1496378315413646", "cc": "91", "phone_number": "9515847444" }' ``` **Responses** **200** Meta's response verbatim ```json { "id": "301234567890123" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Register the number with Cloud API {#registerNumber} `POST /v1/numbers/{phone_number_id}/register` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `registerNumber`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | **Request body** (`application/json`) | Field | Type | Required | Description | |---|---|---|---| | `pin` | string | no | Pattern `^[0-9]{6}$`. | Request example: ```json { "pin": "482913" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/register" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "pin": "482913" }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Deregister the number {#deregisterNumber} `POST /v1/numbers/{phone_number_id}/deregister` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `deregisterNumber`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/deregister" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ## Request an SMS or voice verification code {#requestVerificationCode} `POST /v1/numbers/{phone_number_id}/request-code` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `requestVerificationCode`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `code_method` | `SMS` or `VOICE` | yes | | | `language` | string | yes | | Request example: ```json { "code_method": "SMS", "language": "en_US" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/request-code" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "code_method": "SMS", "language": "en_US" }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ## Verify the code {#verifyCode} `POST /v1/numbers/{phone_number_id}/verify-code` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `verifyCode`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `code` | string | yes | | Request example: ```json { "code": "123456" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/verify-code" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "code": "123456" }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Set or change the two-step verification PIN {#setTwoStepPin} `POST /v1/numbers/{phone_number_id}/two-step` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `setTwoStepPin`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `pin` | string | yes | Pattern `^[0-9]{6}$`. | Request example: ```json { "pin": "482913" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/two-step" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "pin": "482913" }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ## Re-subscribe the number's WABA to WhaBuzz (repair) {#resubscribeWaba} `POST /v1/numbers/{phone_number_id}/subscribe` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `resubscribeWaba`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/subscribe" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Subscribed; connection state recomputed ```json { "phone_number_id": "1013622581841046", "connection_state": "connected", "connection_detail": null } ``` ## Get the WhatsApp business profile {#getBusinessProfile} `GET /v1/numbers/{phone_number_id}/business-profile` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getBusinessProfile`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/business-profile" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Meta's response verbatim ```json { "data": [ { "about": "Strength coaching in Kokapet", "address": "Kokapet, Hyderabad", "description": "Personal training studio", "email": "hello@example.com", "messaging_product": "whatsapp", "profile_picture_url": "https://pps.whatsapp.net/v/t61/…", "websites": [ "https://example.com" ], "vertical": "HEALTH" } ] } ``` ## Update the WhatsApp business profile {#updateBusinessProfile} `POST /v1/numbers/{phone_number_id}/business-profile` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `updateBusinessProfile`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `phone_number_id` | path | string | yes | | **Request body** (`application/json`, required) Request example: ```json { "messaging_product": "whatsapp", "about": "Strength coaching in Kokapet", "websites": [ "https://example.com" ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/numbers/$PHONE_NUMBER_ID/business-profile" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "messaging_product": "whatsapp", "about": "Strength coaching in Kokapet", "websites": [ "https://example.com" ] }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ======================================================================== Source: https://docs.whabuzz.com/api/connect-sessions/ ======================================================================== # Connect sessions > Hosted Embedded Signup links for your own customers. Canonical: https://docs.whabuzz.com/api/connect-sessions/ Hosted Embedded Signup links for your own customers. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`POST /v1/connect-sessions`](#createConnectSession): Create a hosted Embedded Signup link - [`GET /v1/connect-sessions/{session_id}`](#getConnectSession): Get a Connect session ## Create a hosted Embedded Signup link {#createConnectSession} `POST /v1/connect-sessions` Send your customer to `url`. After Meta's flow they return to `return_url?session_id=…&status=connected|failed`. Links expire after one hour. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createConnectSession`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `return_url` | string (uri) | yes | | Request example: ```json { "return_url": "https://app.example.com/settings/whatsapp" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/connect-sessions" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "return_url": "https://app.example.com/settings/whatsapp" }' ``` **Responses** **201** Session ```json { "id": "cs_01JAB3N2R5T8W1Y4A7C0E3G6J9", "url": "https://app.whabuzz.com/connect/9fK2mQ7xL4pV1sN8cR3t", "expires_at": "2026-10-16T11:00:00Z", "status": "open" } ``` ## Get a Connect session {#getConnectSession} `GET /v1/connect-sessions/{session_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getConnectSession`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `session_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/connect-sessions/$SESSION_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Session ```json { "id": "cs_01JAB3N2R5T8W1Y4A7C0E3G6J9", "status": "connected", "result": { "waba_id": "26059971920328384", "phone_number_ids": [ "1013622581841046" ] }, "expires_at": "2026-10-16T11:00:00Z" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/messages/ ======================================================================== # Messages > Send any message type Meta supports. The body is Meta's /messages body plus from. Canonical: https://docs.whabuzz.com/api/messages/ Send any message type Meta supports. The body is Meta's `/messages` body plus `from`. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`POST /v1/messages`](#sendMessage): Send a message - [`POST /v1/messages/read`](#markRead): Mark an inbound message read, optionally showing a typing indicator - [`POST /v1/messages/batch`](#createBatch): Send many messages from one number - [`GET /v1/messages/batch/{batch_id}`](#getBatch): Batch progress - [`GET /v1/messages/batch/{batch_id}/items`](#listBatchItems): Batch items with Meta's response for each - [`POST /v1/messages/batch/{batch_id}/cancel`](#cancelBatch): Cancel the unsent part of a batch ## Send a message {#sendMessage} `POST /v1/messages` The body is Meta's `POST /{phone_number_id}/messages` body plus `from` (your number's phone_number_id or E.164). WhaBuzz adds nothing and checks nothing about content, category or the customer-service window. Meta decides; its answer comes back verbatim. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `sendMessage`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `Idempotency-Key` | header | string | no | Repeat a send safely for 24 hours. Same key + same body returns the stored response; a different body returns 422. | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `from` | string | yes | phone_number_id or E.164 of one of your numbers | | `messaging_product` | string | no | Default `"whatsapp"`. | | `to` | string | yes | | | `type` | string | yes | | Request example, Text: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "recipient_type": "individual", "to": "16505551234", "type": "text", "text": { "preview_url": false, "body": "Your trial is booked for 7:00 AM tomorrow." } } ``` Request example, Template with body parameters: ```json { "from": "+14692311132", "messaging_product": "whatsapp", "to": "16505551234", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Kerry" }, { "type": "text", "text": "31 Oct" } ] } ] } } ``` Request example, Authentication template (you send the copy-code button yourself): ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "template", "template": { "name": "login_code", "language": { "code": "en_US" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "482913" } ] }, { "type": "button", "sub_type": "url", "index": "0", "parameters": [ { "type": "text", "text": "482913" } ] } ] } } ``` Request example, Image by media id: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "image", "image": { "id": "1479537139650973", "caption": "This week's timetable" } } ``` Request example, Document by link: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "document", "document": { "link": "https://example.com/invoice-1042.pdf", "filename": "invoice-1042.pdf" } } ``` Request example, Reply buttons: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "interactive", "interactive": { "type": "button", "body": { "text": "Confirm your 7:00 AM session?" }, "action": { "buttons": [ { "type": "reply", "reply": { "id": "confirm_yes", "title": "Yes" } }, { "type": "reply", "reply": { "id": "confirm_no", "title": "Reschedule" } } ] } } } ``` Request example, List: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "interactive", "interactive": { "type": "list", "body": { "text": "Pick a slot" }, "action": { "button": "Slots", "sections": [ { "title": "Tomorrow", "rows": [ { "id": "slot_0700", "title": "7:00 AM", "description": "Strength" }, { "id": "slot_1800", "title": "6:00 PM", "description": "Conditioning" } ] } ] } } } ``` Request example, Location: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "location", "location": { "latitude": 17.3953, "longitude": 78.3363, "name": "Studio", "address": "Kokapet, Hyderabad" } } ``` Request example, Reaction: ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "type": "reaction", "reaction": { "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFBMDEA", "emoji": "👍" } } ``` Request example, Reply in thread (context): ```json { "from": "1013622581841046", "messaging_product": "whatsapp", "to": "16505551234", "context": { "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFBMDEA" }, "type": "text", "text": { "body": "See you at 7." } } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/messages" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "1013622581841046", "messaging_product": "whatsapp", "recipient_type": "individual", "to": "16505551234", "type": "text", "text": { "preview_url": false, "body": "Your trial is booked for 7:00 AM tomorrow." } }' ``` **Responses** **200** Meta accepted the message. Body is Meta's, verbatim. ```json { "messaging_product": "whatsapp", "contacts": [ { "input": "16505551234", "wa_id": "16505551234" } ], "messages": [ { "id": "wamid.HBgLMTY1MDU1NTEyMzQVAgARGBI5QTNDQTVCM0Q0Q0Q2RTY3RTcA", "message_status": "accepted" } ] } ``` **400** Meta rejected the request (any Meta 4xx is passed through with its own status), or WhaBuzz rejected the body. Meta 131030 passed through (HTTP 400): ```json { "source": "meta", "error": { "message": "(#131030) Recipient phone number not in allowed list", "type": "OAuthException", "code": 131030, "error_data": { "messaging_product": "whatsapp", "details": "Recipient phone number not in allowed list: Add recipient phone number to recipient list and try again." }, "fbtrace_id": "A1b2C3d4E5f6G7h8" } } ``` Meta 132000 passed through (HTTP 400): ```json { "source": "meta", "error": { "message": "(#132000) Number of parameters does not match the expected number of params", "type": "OAuthException", "code": 132000, "error_data": { "messaging_product": "whatsapp", "details": "body: number of localizable_params (1) does not match the expected number of params (2)" }, "fbtrace_id": "B2c3D4e5F6g7H8i9" } } ``` whabuzz_missing_from: ```json { "source": "whabuzz", "error": { "code": "invalid_request", "message": "`from` is required: a phone_number_id or E.164 number of this tenant", "details": null }, "request_id": "req_01JAB3P5S8V1X4Z7B0D3F6H9K2" } ``` **409** Number not connected, or the same Idempotency-Key is still in flight. not_connected: ```json { "source": "whabuzz", "error": { "code": "number_not_connected", "message": "Number 1013622581841046 is not connected: no_verified_endpoint", "details": { "connection_detail": "no_verified_endpoint" } }, "request_id": "req_01JAB3Q6T9W2Y5A8C1E4G7J0M3" } ``` in_flight: ```json { "source": "whabuzz", "error": { "code": "idempotency_conflict", "message": "A request with this Idempotency-Key is still in progress", "details": null }, "request_id": "req_01JAB3R7V0X3Z6B9D2F5H8K1N4" } ``` **422** Idempotency-Key reused with a different body ```json { "source": "whabuzz", "error": { "code": "idempotency_conflict", "message": "Idempotency-Key was used with a different body", "details": null }, "request_id": "req_01JAB3S8W1Y4A7C0E3G6J9M2P5" } ``` **429** Meta throttled the send (passed through) ```json { "source": "meta", "error": { "message": "(#130429) Rate limit hit", "type": "OAuthException", "code": 130429, "error_data": { "messaging_product": "whatsapp", "details": "Cloud API message throughput has been reached." }, "fbtrace_id": "AbCdEf1234567890" } } ``` **502** WhaBuzz could not reach Meta. The outcome is unknown; watch for `message.status` before resending. ```json { "source": "whabuzz", "error": { "code": "meta_unreachable", "message": "Meta did not answer within 15000 ms", "details": { "timeout_ms": 15000 } }, "request_id": "req_01JAB49K4P7S0V3Y6B9E2G5J8M" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 401 | `unauthorized` | Missing or invalid credentials | | 403 | `tenant_not_approved`, `tenant_suspended` | Tenant not approved or suspended | ## Mark an inbound message read, optionally showing a typing indicator {#markRead} `POST /v1/messages/read` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `markRead`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `from` | string | yes | | | `message_id` | string | yes | | | `typing_indicator` | object | no | | | `typing_indicator.type` | `text` | no | | Request example: ```json { "from": "1013622581841046", "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFBMDEA", "typing_indicator": { "type": "text" } } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/messages/read" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "1013622581841046", "message_id": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFBMDEA", "typing_indicator": { "type": "text" } }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Send many messages from one number {#createBatch} `POST /v1/messages/batch` Up to 10,000 Meta message bodies. WhaBuzz paces them to the number's throughput and records Meta's answer for each, verbatim. Each item also produces a `message.outbound` event, and the batch ends with `batch.completed`. WhaBuzz does not retry items Meta rejected. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createBatch`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `from` | string | yes | | | `client_ref` | string | no | Your reference. Unique per tenant; a repeat returns the existing batch. | | `messages` | array of object | yes | | Request example: ```json { "from": "1013622581841046", "client_ref": "renewals-2026-11", "messages": [ { "messaging_product": "whatsapp", "to": "16505551234", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Kerry" }, { "type": "text", "text": "31 Oct" } ] } ] } }, { "messaging_product": "whatsapp", "to": "16505551235", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Ravi" }, { "type": "text", "text": "2 Nov" } ] } ] } } ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/messages/batch" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "1013622581841046", "client_ref": "renewals-2026-11", "messages": [ { "messaging_product": "whatsapp", "to": "16505551234", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Kerry" }, { "type": "text", "text": "31 Oct" } ] } ] } }, { "messaging_product": "whatsapp", "to": "16505551235", "type": "template", "template": { "name": "renewal_reminder", "language": { "code": "en" }, "components": [ { "type": "body", "parameters": [ { "type": "text", "text": "Ravi" }, { "type": "text", "text": "2 Nov" } ] } ] } } ] }' ``` **Responses** **202** Queued ```json { "id": "bat_01JAB3T9X2Z5B8D1F4H7K0M3Q6", "status": "queued", "total": 2, "accepted": 0, "failed": 0, "rate_per_sec": 20, "client_ref": "renewals-2026-11", "created_at": "2026-10-16T10:00:00Z" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 409 | `number_not_connected` | Number not connected | ## Batch progress {#getBatch} `GET /v1/messages/batch/{batch_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getBatch`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `batch_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/messages/batch/$BATCH_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Batch ```json { "id": "bat_01JAB3T9X2Z5B8D1F4H7K0M3Q6", "status": "completed", "total": 2, "accepted": 1, "failed": 1, "started_at": "2026-10-16T10:01:00Z", "completed_at": "2026-10-16T10:01:01Z" } ``` ## Batch items with Meta's response for each {#listBatchItems} `GET /v1/messages/batch/{batch_id}/items` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listBatchItems`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `batch_id` | path | string | yes | | | `status` | query | `pending` or `accepted` or `failed` or `skipped` | no | | | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/messages/batch/$BATCH_ID/items" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Items ```json { "data": [ { "idx": 1, "status": "failed", "http_status": 400, "wamid": null, "response": { "error": { "message": "(#131030) Recipient phone number not in allowed list", "type": "OAuthException", "code": 131030, "error_data": { "messaging_product": "whatsapp", "details": "Recipient phone number not in allowed list: Add recipient phone number to recipient list and try again." }, "fbtrace_id": "A1b2C3d4E5f6G7h8" } }, "event_id": "evt_01JAB3V0Y3A6C9E2G5J8M1P4R7", "sent_at": "2026-10-16T10:01:01Z" } ], "next_cursor": null } ``` ## Cancel the unsent part of a batch {#cancelBatch} `POST /v1/messages/batch/{batch_id}/cancel` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `cancelBatch`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `batch_id` | path | string | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/messages/batch/$BATCH_ID/cancel" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Cancelled ```json { "id": "bat_01JAB3T9X2Z5B8D1F4H7K0M3Q6", "status": "cancelled", "total": 2000, "accepted": 640, "failed": 3 } ``` ======================================================================== Source: https://docs.whabuzz.com/api/media/ ======================================================================== # Media > Upload and download media. WhaBuzz proxies Meta and stores nothing. Canonical: https://docs.whabuzz.com/api/media/ Upload and download media. WhaBuzz proxies Meta and stores nothing. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`POST /v1/media`](#uploadMedia): Upload media to Meta for sending - [`GET /v1/media/{media_id}`](#downloadMedia): Download inbound media - [`DELETE /v1/media/{media_id}`](#deleteMedia): Delete uploaded media from Meta ## Upload media to Meta for sending {#uploadMedia} `POST /v1/media` Stored by Meta, not by WhaBuzz. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `uploadMedia`. **Request body** (`multipart/form-data`, required) | Field | Type | Required | Description | |---|---|---|---| | `file` | string (binary) | yes | | | `type` | string | yes | | | `from` | string | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/media" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -F file=@./photo.jpg \ -F type= \ -F from= ``` **Responses** **200** Meta's response verbatim ```json { "id": "1479537139650973" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 400 | `131030` | Meta's error, passed through with Meta's HTTP status | ## Download inbound media {#downloadMedia} `GET /v1/media/{media_id}` Streams the bytes from Meta. WhaBuzz never stores media. Meta keeps inbound media for a limited time; download promptly. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `downloadMedia`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `media_id` | path | string | yes | | | `from` | query | string | no | Number that received it; needed only when the tenant has several WABAs. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/media/$MEDIA_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** The file Body: `application/octet-stream`. **404** Meta does not know this media id (passed through) ```json { "source": "meta", "error": { "message": "Unsupported get request. Object with ID '1479537139650973' does not exist, cannot be loaded due to missing permissions, or does not support this operation.", "type": "GraphMethodException", "code": 100, "error_subcode": 33, "fbtrace_id": "AxYz0123456789" } } ``` ## Delete uploaded media from Meta {#deleteMedia} `DELETE /v1/media/{media_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `deleteMedia`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `media_id` | path | string | yes | | | `from` | query | string | no | | cURL: ```bash curl -X DELETE "https://api.whabuzz.com/v1/media/$MEDIA_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ======================================================================== Source: https://docs.whabuzz.com/api/templates/ ======================================================================== # Templates > Meta message templates. Bodies and answers are Meta's. Canonical: https://docs.whabuzz.com/api/templates/ Meta message templates. Bodies and answers are Meta's. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/templates`](#listTemplates): List templates - [`POST /v1/templates`](#createTemplate): Submit a template to Meta - [`GET /v1/templates/{template_id}`](#getTemplate): Get a template - [`POST /v1/templates/{template_id}`](#editTemplate): Edit a template - [`DELETE /v1/templates/{template_id}`](#deleteTemplate): Delete a template - [`POST /v1/templates/sync`](#syncTemplates): Re-read every template from Meta - [`GET /v1/templates/library`](#listTemplateLibrary): Browse Meta's template library - [`POST /v1/templates/media-handle`](#createTemplateMediaHandle): Upload a header sample and get a handle for template creation ## List templates {#listTemplates} `GET /v1/templates` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listTemplates`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `waba_id` | query | string | no | | | `status` | query | `APPROVED` or `PENDING` or `REJECTED` or `PAUSED` or `DISABLED` | no | | | `name` | query | string | no | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/templates" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Templates ```json { "data": [ { "id": "1689556908129833", "waba_id": "26059971920328384", "name": "diwali_offer", "language": "en", "category": "MARKETING", "status": "REJECTED", "status_reason": "INVALID_FORMAT: Template body contains variables at the start or end.", "quality_score": null, "parameter_format": "POSITIONAL", "meta_object": { "id": "1689556908129833", "name": "diwali_offer", "language": "en", "status": "REJECTED", "category": "MARKETING", "components": [ { "type": "BODY", "text": "{{1}} off this Diwali" } ] } } ] } ``` ## Submit a template to Meta {#createTemplate} `POST /v1/templates` Body is Meta's `POST /{waba_id}/message_templates` body plus `waba_id`. Response is Meta's. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createTemplate`. **Request body** (`application/json`, required) Request example: ```json { "waba_id": "26059971920328384", "name": "renewal_reminder", "language": "en", "category": "UTILITY", "parameter_format": "POSITIONAL", "components": [ { "type": "BODY", "text": "Hi {{1}}, your membership renews on {{2}}.", "example": { "body_text": [ [ "Kerry", "31 Oct" ] ] } }, { "type": "BUTTONS", "buttons": [ { "type": "QUICK_REPLY", "text": "Renew now" } ] } ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/templates" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "waba_id": "26059971920328384", "name": "renewal_reminder", "language": "en", "category": "UTILITY", "parameter_format": "POSITIONAL", "components": [ { "type": "BODY", "text": "Hi {{1}}, your membership renews on {{2}}.", "example": { "body_text": [ [ "Kerry", "31 Oct" ] ] } }, { "type": "BUTTONS", "buttons": [ { "type": "QUICK_REPLY", "text": "Renew now" } ] } ] }' ``` **Responses** **200** Meta's response verbatim ```json { "id": "1689556908129832", "status": "PENDING", "category": "UTILITY" } ``` **400** Meta rejected the template ```json { "source": "meta", "error": { "message": "Invalid parameter", "type": "OAuthException", "code": 100, "error_subcode": 2388023, "is_transient": false, "error_user_title": "Message template language is being deleted", "error_user_msg": "New en content can't be added while the existing en content is being deleted. Try again in 4 weeks or consider creating a new message template.", "fbtrace_id": "AqXyZ123" } } ``` ## Get a template {#getTemplate} `GET /v1/templates/{template_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getTemplate`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `template_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/templates/$TEMPLATE_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Template ```json { "id": "1689556908129832", "name": "renewal_reminder", "language": "en", "category": "UTILITY", "status": "APPROVED", "quality_score": "GREEN", "meta_object": { "id": "1689556908129832", "status": "APPROVED" } } ``` ## Edit a template {#editTemplate} `POST /v1/templates/{template_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `editTemplate`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `template_id` | path | string | yes | | **Request body** (`application/json`, required) Request example: ```json { "components": [ { "type": "BODY", "text": "Hi {{1}}, your plan renews on {{2}}.", "example": { "body_text": [ [ "Kerry", "31 Oct" ] ] } } ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/templates/$TEMPLATE_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "components": [ { "type": "BODY", "text": "Hi {{1}}, your plan renews on {{2}}.", "example": { "body_text": [ [ "Kerry", "31 Oct" ] ] } } ] }' ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ## Delete a template {#deleteTemplate} `DELETE /v1/templates/{template_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `deleteTemplate`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `template_id` | path | string | yes | | cURL: ```bash curl -X DELETE "https://api.whabuzz.com/v1/templates/$TEMPLATE_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Meta's response verbatim ```json { "success": true } ``` ## Re-read every template from Meta {#syncTemplates} `POST /v1/templates/sync` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `syncTemplates`. **Request body** (`application/json`) Request example: ```json { "waba_id": "26059971920328384" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/templates/sync" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "waba_id": "26059971920328384" }' ``` **Responses** **200** Counts ```json { "waba_id": "26059971920328384", "fetched": 10, "inserted": 0, "updated": 2 } ``` ## Browse Meta's template library {#listTemplateLibrary} `GET /v1/templates/library` Query parameters are passed to Meta unchanged. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listTemplateLibrary`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `search` | query | string | no | | | `topic` | query | string | no | | | `language` | query | string | no | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/templates/library" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Meta's response verbatim ```json { "data": [ { "name": "appointment_reminder_1", "language": "en_US", "category": "UTILITY", "topic": "APPOINTMENTS", "body": "This is a reminder of your upcoming appointment on {{1}} at {{2}}." } ], "paging": { "cursors": { "before": "QVFI", "after": "QVFJ" } } } ``` ## Upload a header sample and get a handle for template creation {#createTemplateMediaHandle} `POST /v1/templates/media-handle` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createTemplateMediaHandle`. **Request body** (`multipart/form-data`, required) | Field | Type | Required | Description | |---|---|---|---| | `file` | string (binary) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/templates/media-handle" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -F file=@./photo.jpg ``` **Responses** **200** Meta's response verbatim ```json { "h": "4::aW1hZ2UvanBlZw==:ARZ…" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/webhooks/ ======================================================================== # Webhooks > Endpoints, signing secrets, deliveries and replay. Canonical: https://docs.whabuzz.com/api/webhooks/ Endpoints, signing secrets, deliveries and replay. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/webhooks`](#listWebhookEndpoints): List endpoints - [`POST /v1/webhooks`](#createWebhookEndpoint): Add an endpoint - [`GET /v1/webhooks/{endpoint_id}`](#getWebhookEndpoint): Get an endpoint - [`PATCH /v1/webhooks/{endpoint_id}`](#updateWebhookEndpoint): Change URL, event types, description or status - [`DELETE /v1/webhooks/{endpoint_id}`](#deleteWebhookEndpoint): Delete an endpoint - [`POST /v1/webhooks/{endpoint_id}/verify`](#verifyWebhookEndpoint): Send the verify ping again - [`POST /v1/webhooks/{endpoint_id}/rotate-secret`](#rotateWebhookSecret): Rotate the signing secret - [`POST /v1/webhooks/{endpoint_id}/replay`](#bulkReplay): Re-send deliveries in a time range - [`GET /v1/webhook-deliveries`](#listDeliveries): List deliveries - [`GET /v1/webhook-deliveries/{delivery_id}`](#getDelivery): Get a delivery with its attempt log - [`POST /v1/webhook-deliveries/{delivery_id}/replay`](#replayDelivery): Re-send one delivery now ## List endpoints {#listWebhookEndpoints} `GET /v1/webhooks` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listWebhookEndpoints`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/webhooks" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Endpoints ```json { "data": [ { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "url": "https://api.example.com/whatsapp/events", "event_types": [ "*" ], "status": "active", "verified_at": "2026-10-16T09:20:00Z", "secret_prefix": "whsec_Zm9v", "consecutive_failures": 0 } ] } ``` ## Add an endpoint {#createWebhookEndpoint} `POST /v1/webhooks` WhaBuzz sends a verify ping right away. Your endpoint must answer 2xx with the `challenge` (plain text, or JSON `{"challenge":"…"}`). Until an endpoint passes, your numbers are not `connected`. The signing secret is in this response only. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createWebhookEndpoint`. **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `url` | string (uri) | yes | | | `description` | string | no | | | `event_types` | array of *` or `message.inbound` or `message.status` or `message.error` or `message.echo` or `message.outbound` or `user.preferences` or `batch.completed` or `template.status` or `template.quality` or `template.category` or `number.quality` or `number.name` or `number.connection` or `account.update` or `account.alerts` or `account.capability` or `account.security` or `token.expiring` or `token.invalid` or `meta.other | no | Default `["*"]`. | Request example: ```json { "url": "https://api.example.com/whatsapp/events", "event_types": [ "*" ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/webhooks" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://api.example.com/whatsapp/events", "event_types": [ "*" ] }' ``` **Responses** **201** Created and verified ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "url": "https://api.example.com/whatsapp/events", "event_types": [ "*" ], "status": "active", "verified_at": "2026-10-16T09:20:00Z", "secret": "whsec_Zm9vYmFyYmF6cXV4MTIzNDU2Nzg5MGFiY2RlZg", "secret_prefix": "whsec_Zm9v" } ``` **422** Created, but the verify ping failed. The endpoint stays pending; fix it and call verify. ```json { "source": "whabuzz", "error": { "code": "webhook_verify_failed", "message": "Endpoint answered 200 without the challenge", "details": { "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "http_status": 200, "body_excerpt": "OK", "secret": "whsec_Zm9vYmFyYmF6cXV4MTIzNDU2Nzg5MGFiY2RlZg" } }, "request_id": "req_01JAB3W1Z4B7D0F3H6K9N2Q5S8" } ``` ## Get an endpoint {#getWebhookEndpoint} `GET /v1/webhooks/{endpoint_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getWebhookEndpoint`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Endpoint ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "url": "https://api.example.com/whatsapp/events", "description": "Production", "event_types": [ "*" ], "status": "active", "verified_at": "2026-10-16T09:20:00Z", "secret_prefix": "whsec_Zm9v", "previous_secret_expires_at": null, "last_success_at": "2026-10-16T10:02:11Z", "consecutive_failures": 0 } ``` ## Change URL, event types, description or status {#updateWebhookEndpoint} `PATCH /v1/webhooks/{endpoint_id}` Changing `url` re-runs the verify ping. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `updateWebhookEndpoint`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | **Request body** (`application/json`, required) Request example: ```json { "event_types": [ "message.inbound", "message.status" ], "status": "active" } ``` cURL: ```bash curl -X PATCH "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "event_types": [ "message.inbound", "message.status" ], "status": "active" }' ``` **Responses** **200** Updated ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "event_types": [ "message.inbound", "message.status" ], "status": "active" } ``` ## Delete an endpoint {#deleteWebhookEndpoint} `DELETE /v1/webhooks/{endpoint_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `deleteWebhookEndpoint`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | cURL: ```bash curl -X DELETE "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Deleted ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "deleted": true } ``` ## Send the verify ping again {#verifyWebhookEndpoint} `POST /v1/webhooks/{endpoint_id}/verify` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `verifyWebhookEndpoint`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/verify" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Passed ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "status": "active", "verified_at": "2026-10-16T09:25:00Z", "response_ms": 84 } ``` **422** Failed ```json { "source": "whabuzz", "error": { "code": "webhook_verify_failed", "message": "Endpoint timed out after 5000 ms", "details": { "http_status": null } }, "request_id": "req_01JAB3X2A5C8E1G4J7M0P3S6U9" } ``` ## Rotate the signing secret {#rotateWebhookSecret} `POST /v1/webhooks/{endpoint_id}/rotate-secret` Both secrets sign every delivery until `previous_secret_expires_at`, so you can deploy the new one without dropping events. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `rotateWebhookSecret`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | **Request body** (`application/json`) | Field | Type | Required | Description | |---|---|---|---| | `overlap_hours` | integer | no | Default `24`. Range 0..168. | Request example: ```json { "overlap_hours": 24 } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/rotate-secret" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "overlap_hours": 24 }' ``` **Responses** **200** New secret (shown once) ```json { "id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "secret": "whsec_bmV3c2VjcmV0MTIzNDU2Nzg5MGFiY2RlZmdoaQ", "secret_prefix": "whsec_bmV3", "previous_secret_expires_at": "2026-10-17T09:30:00Z" } ``` ## Re-send deliveries in a time range {#bulkReplay} `POST /v1/webhooks/{endpoint_id}/replay` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `bulkReplay`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | path | string (uuid) | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `from` | string (date-time) | yes | | | `to` | string (date-time) | yes | | | `status` | array of delivered` or `failed` or `dead | no | Default `["failed","dead"]`. | | `event_types` | array of *` or `message.inbound` or `message.status` or `message.error` or `message.echo` or `message.outbound` or `user.preferences` or `batch.completed` or `template.status` or `template.quality` or `template.category` or `number.quality` or `number.name` or `number.connection` or `account.update` or `account.alerts` or `account.capability` or `account.security` or `token.expiring` or `token.invalid` or `meta.other | no | | Request example: ```json { "from": "2026-10-16T00:00:00Z", "to": "2026-10-16T06:00:00Z", "status": [ "dead" ] } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/webhooks/$ENDPOINT_ID/replay" \ -H "Authorization: Bearer $WHABUZZ_KEY" \ -H "Content-Type: application/json" \ -d '{ "from": "2026-10-16T00:00:00Z", "to": "2026-10-16T06:00:00Z", "status": [ "dead" ] }' ``` **Responses** **202** Queued ```json { "queued": 312 } ``` ## List deliveries {#listDeliveries} `GET /v1/webhook-deliveries` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listDeliveries`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `endpoint_id` | query | string (uuid) | no | | | `status` | query | `pending` or `delivered` or `failed` or `dead` | no | | | `event_id` | query | string | no | | | `from` | query | string (date-time) | no | | | `to` | query | string (date-time) | no | | | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/webhook-deliveries" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Deliveries ```json { "data": [ { "id": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0", "event_id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "event_type": "message.inbound", "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "status": "failed", "attempts": 3, "last_http_status": 503, "next_attempt_at": "2026-10-16T05:15:03Z" } ], "next_cursor": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0" } ``` ## Get a delivery with its attempt log {#getDelivery} `GET /v1/webhook-deliveries/{delivery_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getDelivery`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `delivery_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/webhook-deliveries/$DELIVERY_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Delivery ```json { "id": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0", "event_id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "event_type": "message.inbound", "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "status": "failed", "attempts": 3, "last_http_status": 503, "last_error": "http_5xx", "next_attempt_at": "2026-10-16T05:15:03Z", "attempt_log": [ { "at": "2026-10-16T05:12:03Z", "http_status": null, "ms": 3000, "error": "timeout" }, { "at": "2026-10-16T05:13:00Z", "http_status": 503, "ms": 41, "error": "http_5xx" }, { "at": "2026-10-16T05:14:00Z", "http_status": 503, "ms": 38, "error": "http_5xx" } ], "is_replay": false } ``` ## Re-send one delivery now {#replayDelivery} `POST /v1/webhook-deliveries/{delivery_id}/replay` One synchronous attempt with today's secrets. Works within your retention window. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `replayDelivery`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `delivery_id` | path | string | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/webhook-deliveries/$DELIVERY_ID/replay" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** The new delivery ```json { "id": "dlv_01JAB3Z4C7E0G3J6M9P2S5V8Y1", "status": "delivered", "attempts": 1, "last_http_status": 200, "last_response_ms": 92, "is_replay": true, "replay_of": "dlv_01JAB3Y3B6D9F2H5K8N1Q4T7W0" } ``` **404** Unknown delivery, or the event body is past retention ```json { "source": "whabuzz", "error": { "code": "not_found", "message": "Event body expired under the tenant's 90-day retention", "details": { "reason": "payload_expired" } }, "request_id": "req_01JAB40A5D8F1H4K7N0Q3T6W9Z" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/events/ ======================================================================== # Event log > The event log. Bodies are kept for your retention period (30/90/180/365 days); metadata longer. Canonical: https://docs.whabuzz.com/api/events/ The event log. Bodies are kept for your retention period (30/90/180/365 days); metadata longer. Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/events`](#listEvents): Search the event log - [`GET /v1/events/{event_id}`](#getEvent): Get one event with its full envelope and deliveries ## Search the event log {#listEvents} `GET /v1/events` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listEvents`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `type` | query | `*` or `message.inbound` or `message.status` or `message.error` or `message.echo` or `message.outbound` or `user.preferences` or `batch.completed` or `template.status` or `template.quality` or `template.category` or `number.quality` or `number.name` or `number.connection` or `account.update` or `account.alerts` or `account.capability` or `account.security` or `token.expiring` or `token.invalid` or `meta.other` | no | | | `phone_number_id` | query | string | no | | | `wamid` | query | string | no | | | `wa_id` | query | string | no | | | `error_code` | query | integer | no | | | `from` | query | string (date-time) | no | | | `to` | query | string (date-time) | no | | | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/events" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Event metadata, newest first ```json { "data": [ { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.status", "created_at": "2026-10-16T05:12:03.481Z", "phone_number_id": "1013622581841046", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQVAgASGBQzQUY5QTdGNkU0RTFGMkI3QzFBNDMAAA=", "wa_id": "16505551234", "status": "failed", "error_codes": [ 131049 ] } ], "next_cursor": "evt_01JAB3J8W1R7B3L6P0U4Q5S9XY" } ``` ## Get one event with its full envelope and deliveries {#getEvent} `GET /v1/events/{event_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getEvent`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `event_id` | path | string | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/events/$EVENT_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Event. `envelope` is null once the body is past retention. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "created_at": "2026-10-16T05:12:03.481Z", "envelope": { "note": "Same shape as the message.inbound webhook example (components.examples.EnvelopeInbound)" }, "deliveries": [ { "id": "dlv_01JAB3K9X3T9D5N8R2W6S7U1Z0", "endpoint_id": "3c2b1a09-f8e7-4d6c-b5a4-9382716a5b4c", "status": "delivered", "attempts": 1, "last_http_status": 200 } ] } ``` ======================================================================== Source: https://docs.whabuzz.com/api/billing/ ======================================================================== # Billing > Flat monthly price per number. Never per message. Until billing is switched on, every /v1/billing route answers 503 billing_disabled (details.billing_enabled=false). Canonical: https://docs.whabuzz.com/api/billing/ Flat monthly price per number. Never per message. Until billing is switched on, every /v1/billing route answers 503 billing_disabled (details.billing_enabled=false). Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/billing`](#getBilling): Plan, active numbers and next charge - [`POST /v1/billing/mandate`](#createMandate): Set up autopay - [`GET /v1/billing/invoices`](#listInvoices): Invoices - [`GET /v1/billing/invoices/{invoice_id}`](#getInvoice): Printable invoice (HTML) or JSON with Accept application/json - [`POST /v1/billing/invoices/{invoice_id}/pay`](#payInvoice): Pay a failed invoice now ## Plan, active numbers and next charge {#getBilling} `GET /v1/billing` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getBilling`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/billing" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Billing summary ```json { "plan": "₹500/month first number + ₹250/month each additional, ex-GST", "billing_status": "trialing", "trial_ends_at": "2026-10-30T09:00:00Z", "active_numbers": 2, "next_charge": { "period": "2026-11-01", "amount_paise": 75000, "gst_paise": 13500, "total_paise": 88500, "charge_on": "2026-11-03" }, "mandate": { "status": "not_set_up" } } ``` ## Set up autopay {#createMandate} `POST /v1/billing/mandate` Returns Cashfree's authorisation link. Open it, approve the mandate (UPI Autopay, eNACH or card), and WhaBuzz charges the monthly total on the 3rd. **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `createMandate`. cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/billing/mandate" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **201** Authorisation link ```json { "subscription_id": "wb_sub_a578246e", "authorization_url": "https://sandbox.cashfree.com/pg/view/subscription/…", "max_amount_paise": 200000 } ``` **503** Billing not enabled yet ```json { "source": "whabuzz", "error": { "code": "billing_disabled", "message": "Billing is not enabled yet", "details": { "billing_enabled": false } }, "request_id": "req_01JAB41B6E9G2J5M8P1S4V7Y0B" } ``` ## Invoices {#listInvoices} `GET /v1/billing/invoices` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `listInvoices`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/billing/invoices" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Invoices ```json { "data": [ { "id": "9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d", "number": "WB/2026-27/000001", "period": "2026-11-01", "amount_paise": 75000, "gst_paise": 13500, "total_paise": 88500, "status": "paid", "paid_at": "2026-11-03T04:00:00Z", "html_url": "https://api.whabuzz.com/v1/billing/invoices/9a8b7c6d-5e4f-4a3b-9c2d-1e0f9a8b7c6d" } ] } ``` ## Printable invoice (HTML) or JSON with Accept application/json {#getInvoice} `GET /v1/billing/invoices/{invoice_id}` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `getInvoice`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `invoice_id` | path | string (uuid) | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/billing/invoices/$INVOICE_ID" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **200** Invoice Body: `text/html`. ## Pay a failed invoice now {#payInvoice} `POST /v1/billing/invoices/{invoice_id}/pay` **Auth:** API key (tenant key, or app key with `X-WhaBuzz-Tenant`). **Operation id:** `payInvoice`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `invoice_id` | path | string (uuid) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/billing/invoices/$INVOICE_ID/pay" \ -H "Authorization: Bearer $WHABUZZ_KEY" ``` **Responses** **201** Cashfree checkout link ```json { "payment_url": "https://sandbox.cashfree.com/pg/view/order/…" } ``` ======================================================================== Source: https://docs.whabuzz.com/api/admin/ ======================================================================== # Admin > WhaBuzz staff only (platform admin console session). Canonical: https://docs.whabuzz.com/api/admin/ WhaBuzz staff only (platform admin console session). Base URL `https://api.whabuzz.com`. Every request needs `Authorization: Bearer ` unless the operation says otherwise; see [Authentication](https://docs.whabuzz.com/authentication.md). Errors follow the [two-source contract](https://docs.whabuzz.com/errors.md). Operations on this page: - [`GET /v1/admin/tenants`](#adminListTenants): All tenants (approval queue with status=pending_approval) - [`POST /v1/admin/tenants/{tenant_id}/approve`](#adminApproveTenant): Approve a tenant - [`POST /v1/admin/tenants/{tenant_id}/reject`](#adminRejectTenant): Reject a tenant - [`POST /v1/admin/tenants/{tenant_id}/suspend`](#adminSuspendTenant): Suspend a tenant - [`POST /v1/admin/tenants/{tenant_id}/reinstate`](#adminReinstateTenant): Reinstate a suspended tenant - [`GET /v1/admin/numbers`](#adminListNumbers): Every number across tenants - [`GET /v1/admin/health`](#adminHealth): Pipeline health - [`GET /v1/admin/audit`](#adminAudit): Audit log - [`GET /v1/admin/billing`](#adminBilling): Billing across tenants - [`GET /v1/admin/mail/last`](#adminLastMail): Last email sent to an address (EMAIL_MODE=log only) - [`GET /v1/admin/apps`](#adminListApps): Platform apps - [`POST /v1/admin/apps`](#adminCreateApp): Create a platform app - [`POST /v1/admin/apps/{app_id}/keys`](#adminCreateAppKey): Create an app (platform) API key ## All tenants (approval queue with status=pending_approval) {#adminListTenants} `GET /v1/admin/tenants` **Auth:** Console session token. **Operation id:** `adminListTenants`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `status` | query | `pending_approval` or `active` or `rejected` or `suspended` | no | | | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/tenants" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Tenants ```json { "data": [ { "id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "name": "Acme Fitness", "status": "pending_approval", "created_via": "signup", "contact_email": "owner@acmefitness.in", "website": "https://acmefitness.in", "tax_id": "36ABCDE1234F1Z5", "tax_id_type": "gstin", "email_domain": "acmefitness.in", "flags": [], "created_at": "2026-10-16T08:00:00Z" } ] } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 403 | `forbidden` | Not allowed for this caller | ## Approve a tenant {#adminApproveTenant} `POST /v1/admin/tenants/{tenant_id}/approve` **Auth:** Console session token. **Operation id:** `adminApproveTenant`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | path | string (uuid) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/tenants/$TENANT_ID/approve" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Approved ```json { "id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "status": "active", "approved_at": "2026-10-16T09:00:00Z", "billing_status": "trialing", "trial_ends_at": "2026-10-30T09:00:00Z" } ``` ## Reject a tenant {#adminRejectTenant} `POST /v1/admin/tenants/{tenant_id}/reject` **Auth:** Console session token. **Operation id:** `adminRejectTenant`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | path | string (uuid) | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `reason` | string | yes | | Request example: ```json { "reason": "Website does not match the business name." } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/tenants/$TENANT_ID/reject" \ -H "Authorization: Bearer $CONSOLE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "Website does not match the business name." }' ``` **Responses** **200** Rejected ```json { "id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "status": "rejected", "rejected_reason": "Website does not match the business name." } ``` ## Suspend a tenant {#adminSuspendTenant} `POST /v1/admin/tenants/{tenant_id}/suspend` **Auth:** Console session token. **Operation id:** `adminSuspendTenant`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | path | string (uuid) | yes | | **Request body** (`application/json`, required) | Field | Type | Required | Description | |---|---|---|---| | `reason` | `abuse` or `admin` | yes | | | `note` | string | no | | Request example: ```json { "reason": "abuse", "note": "Spam reports from Meta quality alerts" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/tenants/$TENANT_ID/suspend" \ -H "Authorization: Bearer $CONSOLE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "reason": "abuse", "note": "Spam reports from Meta quality alerts" }' ``` **Responses** **200** Suspended ```json { "id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "status": "suspended", "suspended_reason": "abuse" } ``` ## Reinstate a suspended tenant {#adminReinstateTenant} `POST /v1/admin/tenants/{tenant_id}/reinstate` **Auth:** Console session token. **Operation id:** `adminReinstateTenant`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | path | string (uuid) | yes | | cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/tenants/$TENANT_ID/reinstate" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Active again ```json { "id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "status": "active" } ``` ## Every number across tenants {#adminListNumbers} `GET /v1/admin/numbers` **Auth:** Console session token. **Operation id:** `adminListNumbers`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `connection_state` | query | `pending` or `connected` or `disconnected` | no | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/numbers" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Numbers ```json { "data": [ { "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "tenant_name": "WhaBuzz Demo", "phone_number_id": "1013622581841046", "display_phone_number": "+1 469-231-1132", "connection_state": "connected", "quality_rating": "GREEN", "messaging_limit_tier": "TIER_250", "last_event_at": "2026-10-16T05:12:03Z" } ] } ``` ## Pipeline health {#adminHealth} `GET /v1/admin/health` **Auth:** Console session token. **Operation id:** `adminHealth`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/health" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Health ```json { "retries_due": 4, "oldest_due_retry_at": "2026-10-16T09:58:00Z", "dead_24h": 0, "endpoints_circuit_open": 1, "tokens": { "expiring": 0, "invalid": 0 }, "partitions_through": { "events": "2027-04", "event_payloads": "2027-04", "webhook_deliveries": "2027-04" }, "kv_reconcile": { "last_run_at": "2026-10-16T10:00:00Z", "keys_rewritten": 0 } } ``` ## Audit log {#adminAudit} `GET /v1/admin/audit` **Auth:** Console session token. **Operation id:** `adminAudit`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `tenant_id` | query | string (uuid) | no | | | `action` | query | string | no | | | `limit` | query | integer | no | | | `cursor` | query | string | no | `next_cursor` from the previous page. | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/audit" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Entries ```json { "data": [ { "id": 4012, "tenant_id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "actor_user_id": "6b5a4938-2716-4a5b-8c7d-9e0f1a2b3c4d", "action": "tenant.approve", "target_type": "tenant", "target_id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "details": {}, "created_at": "2026-10-16T09:00:00Z" } ] } ``` ## Billing across tenants {#adminBilling} `GET /v1/admin/billing` **Auth:** Console session token. **Operation id:** `adminBilling`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/billing" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Billing ```json { "billing_enabled": false, "tenants": [ { "tenant_id": "1f2e3d4c-5b6a-4798-8a7b-6c5d4e3f2a1b", "name": "Acme Fitness", "billing_status": "past_due", "past_due_since": "2026-11-03T04:00:00Z", "last_snapshot": { "period": "2026-11-01", "active_numbers": 2, "total_paise": 88500 }, "open_invoices": 1 } ] } ``` ## Last email sent to an address (EMAIL_MODE=log only) {#adminLastMail} `GET /v1/admin/mail/last` **Auth:** Console session token. **Operation id:** `adminLastMail`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `email` | query | string (email) | yes | | cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/mail/last" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** The captured email ```json { "to": "owner@acmefitness.in", "subject": "Confirm your WhaBuzz email", "links": [ "https://app.whabuzz.com/verify-email?token=Qm9…" ], "sent_at": "2026-10-16T08:00:05Z" } ``` **Common errors.** Shape and meanings are on the [Errors page](https://docs.whabuzz.com/errors.md). | HTTP | WhaBuzz code | Meaning | |---|---|---| | 404 | `not_found` | Not found | ## Platform apps {#adminListApps} `GET /v1/admin/apps` **Auth:** Console session token. **Operation id:** `adminListApps`. cURL: ```bash curl -X GET "https://api.whabuzz.com/v1/admin/apps" \ -H "Authorization: Bearer $CONSOLE_TOKEN" ``` **Responses** **200** Apps ```json { "data": [ { "id": "3e53b65e-0000-4000-8000-000000000001", "name": "fisique-crm", "tenants": 1 } ] } ``` ## Create a platform app {#adminCreateApp} `POST /v1/admin/apps` **Auth:** Console session token. **Operation id:** `adminCreateApp`. **Request body** (`application/json`, required) Request example: ```json { "name": "pariq" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/apps" \ -H "Authorization: Bearer $CONSOLE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "pariq" }' ``` **Responses** **201** Created ```json { "id": "6f1e2d3c-4b5a-4697-8a8b-9c0d1e2f3a4b", "name": "pariq" } ``` ## Create an app (platform) API key {#adminCreateAppKey} `POST /v1/admin/apps/{app_id}/keys` **Auth:** Console session token. **Operation id:** `adminCreateAppKey`. **Parameters** | Name | In | Type | Required | Description | |---|---|---|---|---| | `app_id` | path | string (uuid) | yes | | **Request body** (`application/json`, required) Request example: ```json { "name": "Pariq production", "environment": "live" } ``` cURL: ```bash curl -X POST "https://api.whabuzz.com/v1/admin/apps/$APP_ID/keys" \ -H "Authorization: Bearer $CONSOLE_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "name": "Pariq production", "environment": "live" }' ``` **Responses** **201** Key, shown once ```json { "id": "2a3b4c5d-6e7f-4809-9a1b-2c3d4e5f6a7b", "app_id": "6f1e2d3c-4b5a-4697-8a8b-9c0d1e2f3a4b", "prefix": "wb_live_Pa7r", "key": "wb_live_Pa7rQ2xN8mK4vB1cZ6lS9dF3gH5jT0wY7uE2iO4" } ``` ======================================================================== Source: https://docs.whabuzz.com/events/ ======================================================================== # Event catalogue > Every event type WhaBuzz delivers, the envelope that wraps it, and a page per message type with the real payload. Canonical: https://docs.whabuzz.com/events/ Your endpoints receive **events**. Each is a JSON object in a common envelope. For Meta-originated events the `data` field holds Meta's own object verbatim and `raw` holds the complete Meta POST. The pages in this section show, for each message type, the **real Meta payload** (from WhaBuzz's test fixtures) and the **envelope your endpoint receives** for it. ## Event types {#types} | Type | Origin | Meaning | |---|---|---| | `message.inbound` | Meta | A customer sent a message. Every Meta message type, including `unsupported`, `reaction`, `order`, `system`. | | `message.status` | Meta | `sent`, `delivered`, `read` or `failed` for a message you sent. | | `message.error` | Meta | An error Meta reports with no message attached. | | `message.echo` | Meta | A message sent from the WhatsApp Business app on a coexistence number. | | `user.preferences` | Meta | A customer changed marketing preferences. Forwarded only; WhaBuzz keeps no registry. | | `template.status` | Meta | Template review decision or status change. | | `template.quality` | Meta | Template quality rating changed. | | `template.category` | Meta | Meta re-categorised a template. | | `number.quality` | Meta | Number quality rating or messaging tier changed. | | `number.name` | Meta | Display-name review decision. | | `account.update` | Meta | WABA-level notices: restrictions, violations, verification, partner changes. | | `account.alerts` | Meta | Account alerts. | | `account.capability` | Meta | Business capability or limit changes. | | `account.security` | Meta | Security notices. | | `meta.other` | Meta | Any field WhaBuzz has no type for. Never dropped. | | `message.outbound` | WhaBuzz | Every send you make, single or batch, with Meta's response. | | `batch.completed` | WhaBuzz | A batch finished or was cancelled. | | `number.connection` | WhaBuzz | A number's connection state changed. | | `token.expiring`, `token.invalid` | WhaBuzz | Daily business-token health check. | Pages with real payloads are listed in the left navigation. `message.echo`, `user.preferences`, `account.alerts`, `account.capability` and `account.security` carry Meta's change value unchanged; WhaBuzz has no captured sample for them yet, so they have no example here. See [WhaBuzz events](https://docs.whabuzz.com/events/whabuzz-events.md) for the ones WhaBuzz raises itself. Subscribe to `*` to receive all of them, including types added later. ## The envelope {#envelope} API version `2026-10-16`. ```json { "id": "evt_01JAB3K9X2S8C4M7Q1V5R6T0YZ", "type": "message.inbound", "api_version": "2026-10-16", "created_at": "2026-10-16T05:12:03.481Z", "tenant_id": "a578246e-b97f-48e6-ae42-939ec3ccf917", "waba_id": "26059971920328384", "phone_number_id": "1013622581841046", "display_phone_number": "14692311132", "wamid": "wamid.HBgLMTY1MDU1NTEyMzQ…", "wa_id": "16505551234", "user_id": null, "dedupe_key": "msg:wamid.HBgLMTY1MDU1NTEyMzQ…", "data": { "messaging_product": "whatsapp", "metadata": { }, "contacts": [ ], "message": { } }, "raw": { "object": "whatsapp_business_account", "entry": [ ] }, "raw_path": "entry[0].changes[0].value.messages[0]" } ``` | Field | Notes | |---|---| | `id` | `evt_` plus a ULID. Also in the `X-WhaBuzz-Event-Id` header. | | `type` | One of the types above. | | `api_version` | The envelope version. | | `created_at` | When Meta's POST reached WhaBuzz. | | `tenant_id`, `waba_id`, `phone_number_id`, `display_phone_number` | Which business and number the event belongs to. | | `wamid` | The WhatsApp message id, when the event concerns a message. Otherwise null. | | `wa_id` | The customer's WhatsApp id (phone number). Null when absent. | | `user_id` | The customer's business-scoped user id (BSUID), when Meta provides one. Null when absent. | | `dedupe_key` | Identical across redeliveries of the same fact. See [Webhooks](https://docs.whabuzz.com/guides/webhooks.md#dedupe). | | `data` | For messages: Meta's change `value` without `messages[]`, `statuses[]` and `errors[]`, plus the one item under `message`, `status` or `error`. For other Meta fields: the change `value` verbatim plus `field`. | | `raw` | The complete body Meta POSTed. One Meta POST holding three statuses becomes three events, each carrying the same `raw`. Null on WhaBuzz-origin events. | | `raw_path` | Where in `raw` this event's item sits. | The convenience fields are copies of values in `data`. The BSUID field names follow Meta's current documentation and have not yet been re-checked against a live capture. ## Reading the event log {#log} [`GET /v1/events`](https://docs.whabuzz.com/api/events.md#listEvents) lists events with filters; [`GET /v1/events/{event_id}`](https://docs.whabuzz.com/api/events.md#getEvent) returns one with its payload, inside your [retention](https://docs.whabuzz.com/guides/retention.md) window. ======================================================================== Source: https://docs.whabuzz.com/events/whabuzz-events/ ======================================================================== # Events WhaBuzz raises > message.outbound, batch.completed, number.connection and token events. Origin WhaBuzz, raw is null. Canonical: https://docs.whabuzz.com/events/whabuzz-events/ These events come from WhaBuzz, not Meta. They use the same [envelope](https://docs.whabuzz.com/events.md#envelope) with `raw: null` and `raw_path: null`. ## message.outbound {#message-outbound} Emitted for **every** send you make, single or batch, accepted by Meta or refused. It records exactly what WhaBuzz sent and what Meta answered, so your log is complete even if your own process died between sending and storing the result. Its `X-WhaBuzz-Event-Id` was also returned on the send response. `data`: | Field | Meaning | |---|---| | `request` | The body WhaBuzz sent to Meta | | `response` | Meta's response body, verbatim | | `http_status` | Meta's HTTP status | | `batch_id` | `bat_…` for batch items, else null | | `client_ref` | The batch `client_ref`, else null | `dedupe_key` is `out:{event_id}`. ## batch.completed {#batch-completed} A batch finished or was cancelled. Routed by the batch's number. The authoritative counts are on the batch resource: fetch [`GET /v1/messages/batch/{batch_id}`](https://docs.whabuzz.com/api/messages.md#getBatch), and the failures with failures with [`GET /v1/messages/batch/{batch_id}/items?status=failed`](https://docs.whabuzz.com/api/messages.md#listBatchItems). ## number.connection {#number-connection} A number's `connection_state` changed between `pending`, `connected` and `disconnected`. Read the current state and `connection_detail` (`waba_not_subscribed`, `not_registered`, `no_verified_endpoint`, `token_invalid`, `tenant_inactive`) with [`GET /v1/numbers/{phone_number_id}`](https://docs.whabuzz.com/api/numbers.md#getNumber). Conditions are listed under [connection state](https://docs.whabuzz.com/guides/numbers.md#connection-state). A number that loses its last verified endpoint, or whose token is revoked, stops sending with `409 number_not_connected`. Subscribe an endpoint to this event so you find out before your customers do. ## token.expiring and token.invalid {#token} Once a day WhaBuzz checks each connected account's business token with Meta. `token.expiring` fires once per state change when the token is within 7 days of expiry; `token.invalid` fires once per state change when Meta no longer accepts it. Reconnect the number (see [Numbers](https://docs.whabuzz.com/guides/numbers.md#connect-existing)) before or after to restore sending. Each change of state also recomputes the number's connection state, so `token.invalid` is followed by a `number.connection` event with `token_invalid`. ======================================================================== Source: https://docs.whabuzz.com/errors/ ======================================================================== # Errors > The source meta or whabuzz contract, the WhaBuzz error codes, and how to read Meta's errors. Canonical: https://docs.whabuzz.com/errors/ Every error response says who produced it, in the body and in a header. Check `source` first. | `source` | Meaning | HTTP status | |---|---|---| | `whabuzz` | WhaBuzz stopped the request: auth, validation, account state, WhaBuzz's own limits. Meta was not called, or could not be reached. | WhaBuzz's | | `meta` | Meta answered with an error. WhaBuzz returns it verbatim. | **Meta's own status** | The header `X-WhaBuzz-Error-Source: whabuzz` or `meta` repeats it, so you can branch without parsing JSON. ## WhaBuzz errors {#whabuzz-errors} ```json { "source": "whabuzz", "error": { "code": "number_not_connected", "message": "Number 1013622581841046 is not connected.", "details": { "connection_detail": "no_verified_endpoint" } }, "request_id": "req_01JAB3W1Z4B7D0F3H6K9N2Q5S8" } ``` Always log `request_id` (also the `X-WhaBuzz-Request-Id` header). It is what support looks up. | HTTP | `code` | When | `details` | |---|---|---|---| | 400 | `invalid_request` | Malformed JSON, missing or invalid field, missing `X-WhaBuzz-Tenant` | field errors | | 401 | `unauthorized` | Missing, wrong, revoked or expired API key | | | 403 | `forbidden` | The key's role cannot do this | | | 403 | `tenant_not_approved` | Account is `pending_approval` or `rejected` | | | 403 | `tenant_suspended` | Account is `suspended` | `reason` | | 403 | `email_not_verified` | Console sign-in before the email link was used | | | 404 | `not_found` | No such resource, or not yours | `reason: "payload_expired"` when a replay is outside [retention](https://docs.whabuzz.com/guides/retention.md) | | 409 | `number_not_connected` | Send from a number that is not `connected` | `connection_detail` | | 409 | `idempotency_conflict` | Same `Idempotency-Key` still in flight | | | 422 | `idempotency_conflict` | Same `Idempotency-Key` with a different body | | | 422 | `webhook_verify_failed` | Your endpoint failed the [verify ping](https://docs.whabuzz.com/guides/webhooks.md#verify-ping) | `http_status`, `body_excerpt` | | 429 | `rate_limited` | Sign-up, login or password reset only. `Retry-After` is set. | | | 502 | `meta_unreachable` | Graph API did not answer within 15 seconds. **The outcome is unknown.** | | | 400 | `invalid_token` | Sign-up or password-reset link is unknown, used or expired | | | 409 | `conflict` | The resource is in the wrong state for this action, or the WABA is already connected to another account | | | 409 | `limit_reached` | A per-account cap, for example the number of webhook endpoints | | | 503 | `billing_disabled` | Any `/v1/billing` route before billing is switched on | `billing_enabled: false` | | 503 | `billing_not_configured` | Billing is on but the payment gateway is not configured | | | 502 | `billing_gateway_error` | The payment gateway answered with an error | | | 502 | `meta_token_invalid` | The Embedded Signup token failed Meta's validation | | | 500 | `meta_not_configured` | WhaBuzz's Meta credentials are missing (our fault, not yours) | | | 500 | `internal_error` | A fault in WhaBuzz. Retry; report the `request_id` if it persists. The message is always `Internal error`. | | `meta_unreachable` is the one to handle carefully: the message may or may not have been sent. Retry with the same `Idempotency-Key` (see [Idempotency](https://docs.whabuzz.com/guides/idempotency.md)) rather than composing a new send. ## Reading Meta errors {#reading-meta-errors} When Meta refuses a call, you get Meta's HTTP status and Meta's error object under `error`, unchanged: ```json { "source": "meta", "error": { "message": "(#131030) Recipient phone number not in allowed list", "type": "OAuthException", "code": 131030, "error_data": { "messaging_product": "whatsapp", "details": "Recipient phone number not in allowed list: Add recipient phone number to recipient list and try again." }, "error_subcode": 2655007, "fbtrace_id": "AqN2fZtPLm1oV0xK3wRhjQe" } } ``` Reading it: - **`error.code`** is the number to branch on. WhaBuzz never rewrites it. - **`error.error_data.details`** is Meta's plain-language explanation. Show it in your logs. - **`error.fbtrace_id`** is what Meta support asks for. Keep it. - The HTTP status is Meta's: 4xx means your request or account state, 5xx means Meta's side. Do not auto-retry 4xx. The example above, `131030`, is what you get while a WABA is in test mode and the recipient is not on its allowed list. Add the number to the list in Meta's manager, or finish business verification. Common ones: `131047` (re-engagement: the 24-hour window is closed, use a template), `131026` (message undeliverable), `132000` series (template parameter problems), `130429` (throughput), `131056` (pair rate limit), `190` (token expired or invalid; reconnect the number). If Meta's response is not JSON, WhaBuzz wraps it as `{"source":"meta","error":{"raw_body":""}}`. The complete list, with Meta's recommended fix for each, is in Meta's documentation: [Cloud API error codes](https://developers.facebook.com/docs/whatsapp/cloud-api/support/error-codes). ## Errors inside events {#events} Failures after acceptance arrive as events, not HTTP errors: a [`message.status`](https://docs.whabuzz.com/events/message-status.md) with `status: "failed"` carries `status.errors[]` in Meta's format. The same `error.code` numbers apply. ======================================================================== Source: https://docs.whabuzz.com/pricing/ ======================================================================== # Pricing > Flat monthly fee per connected number. Never per message. Canonical: https://docs.whabuzz.com/pricing/ | | | |---|---| | First connected number | **₹500 per month** | | Each additional connected number | **₹250 per month** | | Per-message fees | **None, ever** | Prices are exclusive of GST; 18% GST is added to the invoice. ## What counts {#counts} A number is billed while its connection state is `connected` (see [Numbers](https://docs.whabuzz.com/guides/numbers.md#connection-state)). Numbers that are `pending` or `disconnected` are not billed. Billing is per tenant. ## What you pay Meta {#meta} WhatsApp's own charges (conversation or message rates, depending on Meta's current model) are billed by Meta to your Meta account. WhaBuzz neither marks them up nor sees them on an invoice. See [`message.status`](https://docs.whabuzz.com/events/message-status.md) events for the pricing Meta reports per message. ## Trial and invoices {#trial} New accounts start with a trial and a grace period before suspension for non-payment. Invoices, the payment mandate and payments are managed with [`/v1/billing`](https://docs.whabuzz.com/api/billing.md). The commercial page is at [whabuzz.com/pricing](https://whabuzz.com/pricing). Until billing is switched on, every `/v1/billing` route answers `503 billing_disabled`. ======================================================================== Source: https://docs.whabuzz.com/changelog/ ======================================================================== # Changelog > Changes to the API, events and docs. Canonical: https://docs.whabuzz.com/changelog/ ## 2026-10-16: v1 {#v1} First public release. API version `2026-10-16`. - Tenants, API keys (live and test), platform app keys. - Numbers: Embedded Signup, connect an existing WABA, hosted connect sessions, register, verify, two-step, business profile, migrate. - Messages: Meta's `/messages` body plus `from`, idempotency keys, read receipts, batches of up to 10,000. - Media upload, download and delete (never stored). - Templates: create, edit, delete, sync, library, header media handles. - Webhooks: signed deliveries, verify ping, secret rotation, retries for 24 hours, single and bulk replay. - Event log with retention of 30, 90, 180 or 365 days. - Billing: flat per-number fee. - Errors carry `source: whabuzz | meta`. - This documentation site, with Markdown twins and `/llms.txt`.