What it is
CHANNEL_DISCONNECTED is an account event in Omni Z-API: it is delivered to the workspace’s global webhook (the template webhook, with no instance) and tells you that a channel in the workspace was disconnected, with the reason as a code.
With it, if you integrate many channels you no longer need to subscribe to DISCONNECTED channel by channel to learn about a disconnection.
The channel webhook’s
DISCONNECTED does not change. Its body, rules and formats (DEFAULT, Z_API and CHATWOOT) stay the same, and it does not carry the reason code. If you already subscribe to DISCONNECTED on a channel, you keep receiving it as today. CHANNEL_DISCONNECTED is an additional notice, on the global webhook only.How to subscribe
AddCHANNEL_DISCONNECTED to events when you create or update the global webhook:
- Global webhook only. Channel webhooks and default instance webhooks reject the event with
422. DEFAULTformat only. The global webhook is alreadyDEFAULT.- Independent of other events. The same webhook can subscribe to
CHANNEL_DISCONNECTEDalone, or together with template and billing events. - In the dashboard, subscribing to the event requires the See billing permission, the same one billing events require (Owner and Manager, see Team and roles).
What your server receives
The body is the event:The body never carries a phone number, the provider’s number or account id, a token or a credential.
reason is sent as the provider wrote it and may contain the channel’s number (for example, Disconnected from <number> on WhatsApp Web): it is the same text the dashboard and the channel’s DISCONNECTED already show.Origin
The notice is sent for all three origins. When
origin is USER or BILLING, reasonCode is always null.
Reason codes
One notice per disconnection
- Once per drop. Repetitions of the same disconnection (provider redeliveries, repeated callbacks) don’t generate another notice. The next notice is sent when the channel reconnects and drops again, with a different
id. - The first event’s code. If a later event of the same drop brings another reason, the dashboard shows the new one, but the global webhook does not receive another notice.
One notice per channel
A WhatsApp Business account (WABA) can have several channels. When Meta disconnects the whole account (for example, withPARTNER_REMOVED), one notice is sent for each channel, each with its own instanceId, to the global webhook of the workspace that owns each channel.
This differs from the account restriction notice (ACCOUNT_RESTRICTION), which is sent once per WABA, with the list of affected channels. The difference is intentional: a disconnection is the state of each channel, while a restriction is an account state that does not disconnect the channels.
Together with billing events
When billing disconnects the channel, the global webhook receivesCHANNEL_DISCONNECTED with origin BILLING and the billing event for that path:
There is no guaranteed order between the billing event and
CHANNEL_DISCONNECTED. Each event is delivered only to whoever subscribed to it.
Best practices
- Order is not guaranteed. Sort by
disconnectedAtand discard duplicates byid. - Automate on
reasonCode, never on thereasontext. - Handle a
nullreasonCodeand unknown codes.
Limitations
- The reason code appears only in this notice. Reading the channel through the API (
GET /v1/channels/{id}) does not return it. - There is no retroactive notice. A channel that was already disconnected when the notice went live only generates a notice on its next drop, after it reconnects.
- Some disconnections don’t go through the provider event flow and generate no notice: for example, a WhatsApp Web disconnection confirmed by the provider without a return event, and a billing cut-off of a WhatsApp Web channel without an active subscription.