Skip to main content

Check connection status

GET /v1/numbers/{id}/status returns the live connection state of one WhatsApp number.
Response:
This endpoint reflects the same connection state shown on the Numbers page in the dashboard (as does GET /v1/numbers/{id}/connect).

When to use it

  • GET /v1/numbers does not force a mass refresh of connection state — call this endpoint per number when you need an up-to-date check.
  • Poll it after showing a QR code / pairing code to detect when the customer completes the connection (or rely on the number.connected webhook instead).

States

Treat state === "OPEN" as the definitive “ready to send” flag for the connection. An unpaid extra-number charge blocks sending without changing it — see the note below.
A 200 does not mean connected. A number created through Meta remote pairing answers 200 with PENDING from the moment the link is generated. Branch on state, never on the HTTP status alone.
/status does not report an unpaid extra-number charge. This endpoint answers for the connection only, and its response carries neither extraChargeUnpaidSince nor extraChargeDisconnectAt. A number whose extra-number charge was refused still answers OPEN here, while every send from it is refused with 409 NUMBER_BLOCKED (reason: "extra_charge_unpaid"). Read the two fields from GET /v1/numbers or GET /v1/numbers/{id}. There they are top-level fields of the number — not part of health.

Meta remote pairing: PENDING, EXPIRED and expiresAt

POST /v1/numbers/remote-pairing with provider: "META" creates the number right away, so it shows up as “awaiting connection” while your end user is still inside the Facebook dialog. Polling its status during that window answers:
expiresAt is the end of the pairing window. After it passes, the same call answers state: "EXPIRED" — the number will never connect on its own, so stop polling and generate a new link. A number in this state is not billed (it is excluded from your plan’s number count and from your capacity) and is removed automatically 24h after it was created, so abandoned signups do not pile up in GET /v1/numbers.
Previously both cases answered 404, indistinguishable from an id that does not exist, which left polling loops with no way to tell “still waiting” from “gone”.

How fresh is the answer: stale, checkedAt, lastKnownAt

Every 200 carries stale, plus exactly one of the two timestamps: stale: true always comes with state: "OPEN". The remembered value is only served when the stored state was already OPEN; for a number that was not OPEN, a provider that does not answer produces a 503 instead (see below). Meta (official Cloud API) numbers answer { "id": "…", "state": "OPEN", "stale": false } and carry neither timestamp — they are remote-managed, nothing is probed for them, so there is no reading to date.
On a Meta number this endpoint is not a health check. Once the number exists with a Meta phone id, state here is always OPEN — it does not consult the number’s health at all. A number Meta has RESTRICTED, or whose quality dropped to RED, still answers OPEN here while GET /v1/numbers and GET /v1/numbers/{id} answer DISCONNECTED for the same number at the same instant.So /status on a Meta number answers exactly one question: does this number exist and is it past the signup window? (PENDING → EXPIRED → OPEN). For whether we are currently sending on the number at all, read health.sendable from GET /v1/numbers/{id} — that is the field the state on the other two routes is derived from. It is our verdict about the number, not Meta’s answer about the next send; the caveats are on that field.
On a native web (QR-paired) number none of this applies: /status really does probe the provider, and stale / checkedAt / lastKnownAt describe that probe.

Errors

The code on a 503 tells you whether retrying is worth it:
Fixed: this endpoint used to answer 503 “WhatsApp provider not configured” for every number that was not already OPEN whenever the platform’s own number was disconnected. That coupling is gone — a 503 now describes this number’s own provider.