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.
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:
Examples
An iMessage number finishing its caller-ID verification while WhatsApp is still going:
A standard number, whose whole lifecycle is one event:
WhatsApp failing with a cooldown — the number keeps working:
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. - 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.