number.status_changed
number.status_changed
Emitted every time one of your Dial numbers’ capabilities moves. Provisioning a number returns as soon as the number itself is held, which can be before every channel on it works; this event tells you the moment each one becomes usable — so you can react instead of polling GET /api/v1/numbers/{id} in a loop.
Capabilities settle separately
A number is not “provisioning” as a whole. Each capability has its own clock:
So two capabilities can be in flight, and they can disagree: a number whose WhatsApp was declined still sends SMS, places calls and messages over iMessage. That is why every capability reports its own status, and why errors live only on the capability that owns them — there is no number-level error field.
The number’s own status
status folds the capabilities into one value:
ready and degraded are both terminal, so waiting for “either” always resolves. Wait for only ready and you can wait forever: WhatsApp can decline a number outright, and no retry will change that — the number is finished setting up, just not perfectly.
Anything still in flight outranks a failure. A number with a failed WhatsApp track and a caller-ID check still running is unsettled, not degraded: it has not finished trying, and a terminal status would invite you to stop waiting.
A number can also leave ready and become degraded long after setup finished — that is what a banned capability means, and, for as long as it lasts, a paused one. Treat ready as the number’s state today, not a promise about tomorrow, and keep handling this event for the life of the number rather than only while you are waiting for setup.
Schema
Shares the common event envelope (id, object, type, version, createdAt, relatedObject). relatedObject is { id: <phoneNumberId>, type: "phone_number", url: "/api/v1/numbers/<phoneNumberId>" }. The envelope’s createdAt is when the transition happened.
This event’s payload is at version: 2. Every other event is at version: 1 — the version is per event type, not global, so branch on (type, version) rather than on version alone. Version 1 of this payload was flat (setupStatus, setupError, and capabilities as a string array); it could report only the line’s own setup and had nowhere to put a WhatsApp failure or its cooldown.
Each entry in capabilities:
Capability status values
failed and banned are both terminal but they are not the same ending. failed is a setup that never finished; banned is a working channel taken away afterwards, so previousStatus is "ready" and retryAvailableAt is always null. No retry recovers a banned channel — registering it on the number again is the only route back.
paused is the temporary one. It only ever follows ready (previousStatus is "ready"), retryAvailableAt is always null, and sending on the channel is refused with 503 whatsapp_unavailable until it ends. When it ends you get a second event moving the capability back to ready with previousStatus: "paused". A pause applies to some lines and not others, so it arrives as one event per affected number rather than one for your whole account.
A banned capability leaves the number’s capabilities array, because the number can no longer do that thing. A paused one stays: the line still receives WhatsApp, and only sending is held, which whatsapp.status tells you. The number’s other channels are untouched: a number whose WhatsApp is banned or paused still sends SMS and takes calls.
Examples
An iMessage number finishing its caller-ID verification while WhatsApp is still going:
A standard number, whose whole lifecycle is one event:
WhatsApp connected on a number you already hold, registered and now warming up — calling is released, the number stays unsettled:
About 6 hours later, the warm-up finishes and the number is ready:
WhatsApp failing with a cooldown — the number keeps working:
A live WhatsApp line withdrawn months after it was set up. Note previousStatus: "ready", the number
falling to degraded, and whatsapp leaving capabilities — while SMS and calling carry on:
Waiting for a number to finish setting up:
Filters match top-level data fields, so status, previousStatus, number and phoneNumberId are filterable; capabilities is nested, so read it from the payload rather than filtering on it.
When it fires
- Once per observable change. A number’s setup involves several internal steps that map to the same capability status, and those are not published — you get an event when a capability’s status actually changes, not once per internal write.
- Every number gets a first event,
previousStatus: nullandchanged: [], published as it is created — so a consumer waits on the same event whichever kind of number it provisioned, and never has to know which kind that was. A standard number isreadythere and emits nothing further. On the presence-based stream that first event can be published before the provisioning HTTP response reaches you, so a listener that subscribes afterwards may miss it; the response already told you the status. Webhook delivery is queued and retried, so a webhook consumer always receives it. - A pause and its end each fire, on every affected number.
ready→pausedwhen Dial pauses WhatsApp sending on a line, andpaused→readywhen it resumes. A number bought while a pause is on reportspausedfrom the moment its WhatsApp is set up, and moves toreadywhen the pause ends. - A ban fires long after setup is over. Every other trigger here happens while a number is settling;
bannedcan arrive months later and moves areadynumber todegraded. If you stop consuming this event once a number reachesready, you will not find out that a channel stopped working. - Retrying a failed capability emits a fresh event, moving the number back to
unsettled, followed by another when it resolves. Each cycle carries its own eventids; nothing is collapsed into the earlier attempt. Deduplicate on the envelopeid. changedcan name two capabilities. A WhatsApp track reaching a terminal state is what releases a caller-ID-verified line from waiting on it, sowhatsappandcallsettle together and are reported in one event rather than two half-truths.- Releasing a number emits nothing — the number stops existing, and there is no status for that.