Buy a WhatsApp-ready number, bring your own, verify and register it with Meta, check that it is alive and follow its lifecycle events.
Every WhatsApp account sits on a phone number. You can buy one through Pozy, which arrives already verified with Meta and can also make calls and send SMS, or connect a number you already own. This page covers the WhatsApp side of numbers: getting one ready, keeping it registered and knowing when it stops working. Searching inventory, country rules, KYC and porting are in Phone, SMS & voice.
#Buy a number for WhatsApp
Call POST /v1/phone-numbers/purchase with the profile the number should belong to. connectWhatsapp is true by default, so the purchase hands straight over to WhatsApp signup, where the new number appears as Verified in Meta's picker.
curl -X POST https://api.pozy.ai/v1/phone-numbers/purchase \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"profileId": "6710c4e2b9a1f03d8e5c7a21",
"country": "US",
"numberType": "local",
"areaCode": "415",
"wantsWhatsapp": true,
"purchaseIntentId": "bakery-main-line"
}'const res = await fetch("https://api.pozy.ai/v1/phone-numbers/purchase", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
profileId: "6710c4e2b9a1f03d8e5c7a21",
country: "US",
numberType: "local",
areaCode: "415",
wantsWhatsapp: true,
purchaseIntentId: "bakery-main-line",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data);import os
import requests
H = {"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"}
resp = requests.post(
"https://api.pozy.ai/v1/phone-numbers/purchase",
headers=H,
json={
"profileId": "6710c4e2b9a1f03d8e5c7a21",
"country": "US",
"numberType": "local",
"areaCode": "415",
"wantsWhatsapp": True,
"purchaseIntentId": "bakery-main-line",
},
timeout=30,
)
print(resp.json())purchaseIntentId makes the purchase safe to retry: sending the same id again returns the number you already bought (status: "already_purchased") instead of buying a second one.
| Country type | What happens |
|---|---|
| Instant (the US and others) | The number is ready in seconds |
| Regulated | A one-time KYC form first. The number activates in 1 to 3 business days and whatsapp.number.activated fires when it is ready. |
A number needs a payment method on the workspace. Without one the purchase returns 402 payment_required. Pricing is per number per month (WhatsApp pricing).
The /v1/whatsapp/phone-numbers/* purchase, search and KYC routes still work but are deprecated. Use the /v1/phone-numbers/* routes, which take the same inputs.
#Add WhatsApp to a number you bought for calls or SMS
If a Pozy number was bought without WhatsApp, start Meta's verification with POST /v1/phone-numbers/{id}/whatsapp/request-code (method SMS or VOICE). Pozy receives the code on the number itself, so you do not have to relay it. Then connect the number through signup as usual.
If Meta refuses the number for WhatsApp, a number that is already live keeps working for calls and SMS and the call returns 409 number_not_whatsapp_eligible. A number that was never live is swapped for an eligible one at no cost, and the response says replaced: true with the newPhoneNumber.
#Move a number to another profile
A Pozy number belongs to one profile, and connecting it from any other profile returns 409. To re-home it, call PATCH /v1/whatsapp/phone-numbers/{id}/profile with the new profileId. That moves the number and every account built on it (WhatsApp, calls, SMS) together. id is the number id from GET /v1/phone-numbers, not an account id.
#Bring your own number
A number on your own carrier connects through Embedded Signup or a Meta token. It works for WhatsApp messages and calls, but Pozy cannot add SMS or phone-network calling to it, because there is no Pozy line behind it. GET /v1/phone-numbers lists it under connected, not numbers.
Meta occasionally asks a number you brought from another provider to verify again. When that happens:
- Request a code with
POST /v1/accounts/{accountId}/whatsapp/request-code(SMSorVOICE). The code goes to the business's own phone, so someone there has to read it. You can request one every 10 minutes, and Meta adds its own cooldown. - Submit it with
POST /v1/accounts/{accountId}/whatsapp/verify-code. - Finish with
POST /v1/accounts/{accountId}/whatsapp/register. Verifying alone does not put the number back on the Cloud API.
#Register a number that has a PIN
If the number has two-step verification turned on, the connect flow cannot register it on its own and Meta rejects the registration (error 133005). The account still looks connected, but every send fails with (#200) You do not have the necessary permission.
Run the registration again with the right PIN. Pozy uses the PIN for this call only and does not store it.
curl -X POST https://api.pozy.ai/v1/accounts/6712a9d4c0e3b58f1a7d2e64/whatsapp/register \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "pin": "205718" }'A 422 means Meta still refused, most often a wrong PIN. Check it in WhatsApp Manager and try again.
#Check that a number is alive
A WhatsApp channel can die without much warning, for example when a coexistence number is disconnected from the phone. Do not rely on the absence of an account.disconnected event; check directly.
| Check | What it tells you |
|---|---|
GET /v1/whatsapp/number-info |
A live read from Meta. 200 means Meta is serving the number. 400 with Meta error 100, subcode 33 means it is gone until you reconnect. |
GET /v1/accounts/{accountId}/health |
Runs the same live read and reports it as platformConnection.status: connected, disconnected or unknown (the read failed for another reason, such as a timeout). A valid token does not mean the channel is alive. |
GET /v1/whatsapp/business-profile |
Not a liveness check. It can return a full profile for a dead number. |
platformStatus in GET /v1/accounts |
A stored value refreshed by periodic checks. It can be hours or days old. Compare it with metadata.metaStatusCheckedAt before acting on it. |
Health also reports messagingRestriction when Meta refuses sends for a reason other than the channel itself:
| Meta code | Reason |
|---|---|
131042 |
A payment problem on the WABA |
131031 |
The WhatsApp Business Account is locked |
368 |
A policy block |
The restriction appears on the first refused send and clears on the next delivered message.
#Number lifecycle
Numbers bought through Pozy move through statuses, and Pozy sends an event on each step. The event names start with whatsapp.number. for historical reasons, but they fire for every Pozy number, including ones used only for calls or SMS.
| Status | Reached by | Event |
|---|---|---|
pending_regulatory |
KYC submitted in a regulated country | whatsapp.number.kyc_submitted (hosted KYC links only) |
pending_regulatory (blocked) |
The regulator wants more information or an ID check | whatsapp.number.action_required, whatsapp.number.verification_required |
regulatory_declined |
The regulator declined the order. You are not billed. Fix and resubmit with remediation. | whatsapp.number.declined |
active |
Setup finished; ready to connect | whatsapp.number.activated |
suspended |
For example a failed payment (reason: "payment_failed") |
whatsapp.number.suspended |
active again |
The issue was fixed | whatsapp.number.reactivated |
released |
Released by you or after an unresolved suspension. Final. | whatsapp.number.released |
Numbers in instant countries skip the review states and go straight to active.
#Release a number
DELETE /v1/phone-numbers/{id} releases a number you bought. It disconnects the WhatsApp account on it, stops the monthly charge and makes the number unusable. This cannot be undone.
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/phone-numbers |
List phone numbers |
POST /v1/phone-numbers/purchase |
Purchase phone number |
GET /v1/phone-numbers/{id} |
Get phone number |
DELETE /v1/phone-numbers/{id} |
Release phone number |
POST /v1/phone-numbers/{id}/whatsapp/request-code |
Request the WhatsApp verification code for a number |
PATCH /v1/whatsapp/phone-numbers/{id}/profile |
Move a number to another profile |
GET /v1/whatsapp/number-info |
Get number status |
POST /v1/accounts/{accountId}/whatsapp/request-code |
Request a Meta re-verification code for a BYO WhatsApp number |
POST /v1/accounts/{accountId}/whatsapp/verify-code |
Verify the Meta re-verification code for a BYO WhatsApp number |
POST /v1/accounts/{accountId}/whatsapp/register |
Register a connected WhatsApp number on the Cloud API |
GET /v1/accounts/{accountId}/health |
Check account health |
#Webhook events
| Event | When it fires |
|---|---|
account.disconnected |
Account disconnected. |
whatsapp.number.activated |
WhatsApp number activated. |
whatsapp.number.declined |
WhatsApp number declined. |
whatsapp.number.action_required |
WhatsApp number action required. |
whatsapp.number.verification_required |
WhatsApp number verification-required. |
whatsapp.number.suspended |
WhatsApp number suspended. |
whatsapp.number.reactivated |
WhatsApp number reactivated. |
whatsapp.number.released |
WhatsApp number released. |
whatsapp.number.kyc_submitted |
WhatsApp number KYC submitted. |
phone_number.stock_available |
Phone-number stock available. |