Skip to main content

Number Management

Check account and number health, register or deregister a number, verify it, rotate its two-step PIN, edit its business profile, block users, and manage QR codes and short links.

These endpoints manage a WhatsApp number after it is connected. Connecting, listing, linking a bot, pausing auto-reply, disconnecting and deleting are on WhatsApp API; ice breakers and commands are under Conversational automation.

Base path: /api/v1/whatsapp

Every path below takes CallMissed's ids, never Meta's: {account_id} is the id from GET /accounts and {phone_id} is the id from GET /phone_numbers. Both are scoped to your workspace, and an id from another workspace returns the same 404 as one that does not exist.

AreaEndpointsScope
HealthAccount health, refresh, number healthwhatsapp:read; refresh needs whatsapp:write
RegistrationRegister, deregister, request code, verify code, two-step PINwhatsapp:write
Business profileRead and updatewhatsapp:read / whatsapp:write
Blocked usersList, block, unblockwhatsapp:read / whatsapp:write
QR codes and short linksList, create, get, update, deletewhatsapp:read / whatsapp:write

Errors common to every route on this page

CodeMeaning
400No business token is on file for the number. Reconnect it through Embedded Signup
403The API key is missing the scope in the route's signature line
404The account, number or QR code is not on your workspace
422The body failed validation, or WhatsApp rejected the request. The detail is a short, actionable sentence
429WhatsApp's rate limit for this number or action was reached. Wait, then retry
500The stored credentials for the number could not be read. Reconnect the number
502WhatsApp failed. Retry; contact support if it persists

WhatsApp's raw error text and numeric codes are never echoed back. Each failure carries one of our own sentences in detail.

Health

Health tells you which link in the chain (app, business, WhatsApp Business Account, phone number) is blocking sends, and why. The two GET routes return the last stored verdict without calling WhatsApp, so they are cheap to poll. POST .../health/refresh re-reads it live.

Get account health

GET /api/v1/whatsapp/accounts/{account_id}/health · scope whatsapp:read

curl https://api.callmissed.com/api/v1/whatsapp/accounts/1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d/health \
  -H "Authorization: Bearer cm_your_api_key"

Response (200 OK)

{
  "account_id": "1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d",
  "waba_id": "102290129340398",
  "health_status": {
    "can_send_message": "AVAILABLE",
    "entities": [
      { "entity_type": "BUSINESS", "id": "441329482726", "can_send_message": "AVAILABLE" },
      { "entity_type": "WABA", "id": "102290129340398", "can_send_message": "AVAILABLE" }
    ]
  },
  "health_checked_at": "2026-09-30T08:15:00Z",
  "business_verification_status": "verified",
  "account_review_status": "APPROVED",
  "account_status": "ACTIVE",
  "account_restriction_reason": null,
  "payment_setup_complete": true
}
FieldTypeNotes
account_idUUIDCallMissed's account id
waba_idstringMeta's WABA id
health_statusobject, nullableWhatsApp's health document, passed through as WhatsApp returned it, including the per-entity breakdown and any reason. null until the first refresh. New entity types can appear, so do not switch exhaustively on it
health_checked_atdatetime, nullableWhen health was last read successfully. null means it has never been read, not that the account is healthy
business_verification_statusstring, nullableMeta business verification. Required before you can create authentication templates. Verification itself is done in Meta Business Manager, not over any API
account_review_statusstringPENDING, APPROVED or REJECTED
account_statusstringACTIVE, or a restricted state
account_restriction_reasonstring, nullableSet when WhatsApp restricts the account. null while healthy
payment_setup_completebooleanWhether a payment method is attached to the WABA. Payment methods are added in WhatsApp Manager

Refresh account health

POST /api/v1/whatsapp/accounts/{account_id}/health/refresh · scope whatsapp:write

No body. Re-reads, live from WhatsApp, the account's health, its business verification and review status, and the health of every number under the account. Each read is independent: if some succeed and others fail, the successful ones are saved and returned, and health_checked_at only moves for what was actually read.

curl -X POST https://api.callmissed.com/api/v1/whatsapp/accounts/1a2b3c4d-5e6f-7a8b-9c0d-1e2f3a4b5c6d/health/refresh \
  -H "Authorization: Bearer cm_your_api_key"

Returns the account health object above. 409 if no number on the account has a usable business token (reconnect one), 502 if every read failed.

It needs whatsapp:write rather than whatsapp:read because it spends the account's WhatsApp rate-limit budget and updates stored state.

Get number health

GET /api/v1/whatsapp/phone_numbers/{phone_id}/health · scope whatsapp:read

A number can be blocked while its account is healthy, and the other way round, so it has its own health. Refresh it with the account refresh above.

curl https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/health \
  -H "Authorization: Bearer cm_your_api_key"

Response (200 OK)

{
  "phone_id": "9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d",
  "phone_number_id": "1234567890",
  "display_phone_number": "+91 80802 47309",
  "health_status": { "can_send_message": "AVAILABLE" },
  "health_checked_at": "2026-09-30T08:15:00Z",
  "quality_rating": "GREEN",
  "name_status": "APPROVED",
  "code_verification_status": "VERIFIED",
  "throughput_level": "STANDARD",
  "messaging_limit": null,
  "messaging_limit_tier": "TIER_1K",
  "registration_status": "REGISTERED",
  "registration_error": null,
  "is_active": true
}
FieldTypeNotes
phone_idUUIDCallMissed's number id
phone_number_idstringMeta's phone number id
display_phone_numberstringThe number as customers see it
health_statusobject, nullableWhatsApp's health document for this number, passed through. null until the first refresh
health_checked_atdatetime, nullableWhen it was last read successfully
quality_ratingstringGREEN, YELLOW, RED, NA or UNKNOWN. Treat it as an open string
name_statusstringDisplay-name approval. Free-form sends only work while this is APPROVED or AVAILABLE_WITHOUT_REVIEW
code_verification_statusstringVERIFIED once the number has been verified
throughput_levelstringSTANDARD today
messaging_limitstring, nullableReserved for WhatsApp's portfolio-level messaging limit, which is shared by every number in the same business portfolio. May be null; read messaging_limit_tier until it is set
messaging_limit_tierstringBusiness-initiated messaging limit tier, for example TIER_1K
registration_statusstringPENDING, REGISTERED, FAILED or DEREGISTERED
registration_errorstring, nullableWhy the last registration failed
is_activebooleanfalse once the number is disconnected

Registration and verification

Register a number

POST /api/v1/whatsapp/phone_numbers/{phone_id}/register · scope whatsapp:write

Registers a connected number on the WhatsApp Cloud API. Use it to retry a registration that failed during onboarding (registration_status is FAILED), or to re-register after a deregister.

WhatsApp allows 10 registrations per number in any rolling 72 hours. The 11th attempt locks the number for 72 hours and returns 429. Call this only from a deliberate user action, never from a retry loop. Deregister counts against the same quota.

If the number already has a two-step verification PIN on file, it is reused, because WhatsApp requires the existing PIN and a wrong one burns quota. Otherwise a new PIN is generated and kept for future re-registrations. To set your own PIN, use Rotate the two-step PIN.

FieldTypeRequiredNotes
data_localization_regionstring, exactly 2 charsNoISO 3166-1 alpha-2 country for data-at-rest residency, from WhatsApp's supported list. It cannot be changed in place: deregister, then register with the new value
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/register \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "data_localization_region": "IN" }'

Response (200 OK)

{ "ok": true, "error": null }

On success registration_status becomes REGISTERED. On failure it becomes FAILED with registration_error set.

CodeMeaning
409The stored two-step PIN cannot be used, or the number was recently deleted and WhatsApp has not finished removing it. Reset the PIN in WhatsApp Manager, or wait about 5 minutes
429The 10-per-72-hours registration limit was reached. Wait until WhatsApp unblocks the number

Deregister a number

POST /api/v1/whatsapp/phone_numbers/{phone_id}/deregister · scope whatsapp:write

No body. Deregisters the number on WhatsApp only: the number stays connected and active in your workspace, and registration_status moves to DEREGISTERED. Use it mid-workflow, for example to change data_localization_region by deregistering and registering again.

To stop using a number altogether, use Disconnect instead, which also unsubscribes webhooks and deactivates the number locally.

curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/deregister \
  -H "Authorization: Bearer cm_your_api_key"

Returns { "ok": true, "error": null }. Shares the registration quota above.

Request a verification code

POST /api/v1/whatsapp/phone_numbers/{phone_id}/request_code · scope whatsapp:write

Asks WhatsApp to send a verification code to the number by SMS or voice call. This is number verification, separate from Cloud API registration, and does not use the registration quota.

FieldTypeRequiredNotes
code_methodstringNoSMS (default) or VOICE. Case-insensitive
languagestring, 2 to 10 charsNoLanguage of the code message, for example en or en_US. Default en_US. Passed to WhatsApp as given
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/request_code \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "code_method": "SMS", "language": "en_US" }'

Returns { "ok": true, "error": null }. 409 if the number is already verified (code_verification_status is VERIFIED), so no code is sent.

Submit the verification code

POST /api/v1/whatsapp/phone_numbers/{phone_id}/verify_code · scope whatsapp:write

FieldTypeRequiredNotes
codestring, 1 to 16 charsYesThe code WhatsApp sent to the number
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/verify_code \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "code": "123456" }'

Returns { "ok": true, "error": null } and sets code_verification_status to VERIFIED. A wrong or expired code returns 422. The code is never stored or echoed back.

Rotate the two-step PIN

POST /api/v1/whatsapp/phone_numbers/{phone_id}/two_step_pin · scope whatsapp:write

Changes the number's two-step verification PIN in place. It does not deregister the number and does not use the registration quota. The new PIN is kept only once WhatsApp accepts it, and is used for later re-registrations. It is never returned by any endpoint.

FieldTypeRequiredNotes
pinstring, exactly 6 digitsYesThe new PIN
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/two_step_pin \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "pin": "482913" }'

Returns { "ok": true, "error": null }.

Two-step verification cannot be disabled through any API. Once enabled it stays enabled, and this endpoint can only change the PIN. To turn it off, use WhatsApp Manager.

Business profile

The profile is what a customer sees when they tap your business name in a chat: about line, address, description, email, websites, industry and profile picture. It belongs to a number, not the account, so two numbers on one account have independent profiles.

Get the profile

GET /api/v1/whatsapp/phone_numbers/{phone_id}/business_profile · scope whatsapp:read

Read live from WhatsApp, so edits made in WhatsApp Manager show up immediately.

curl https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/business_profile \
  -H "Authorization: Bearer cm_your_api_key"

Response (200 OK)

{
  "phone_id": "9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d",
  "phone_number_id": "1234567890",
  "about": "Fresh coffee, delivered.",
  "address": "12 MG Road, Bengaluru 560001",
  "description": "Specialty coffee roasted in small batches and shipped across India.",
  "email": "support@acme.example",
  "vertical": "RETAIL",
  "websites": ["https://acme.example"],
  "profile_picture_url": "https://pps.whatsapp.net/v/t61.24694-24/...",
  "last_synced_at": "2026-09-30T08:20:00Z",
  "stale": false
}
FieldTypeNotes
aboutstring, nullableThe short about line
addressstring, nullableBusiness address
descriptionstring, nullableLonger description
emailstring, nullableContact email
verticalstring, nullableIndustry, one of the values listed under Update the profile
websitesstring[], nullableWebsite URLs
profile_picture_urlstring, nullableRead-only. A temporary URL for the current picture
last_synced_atdatetime, nullableWhen the profile was last read from WhatsApp
stalebooleantrue when WhatsApp could not be reached and the last stored copy was returned instead. Without a stored copy the error is returned

Update the profile

POST /api/v1/whatsapp/phone_numbers/{phone_id}/business_profile · scope whatsapp:write

A partial update. Only the fields you send change; omitted fields are left as they are. Send a field as null to clear it. At least one field is required (400 otherwise).

FieldTypeRequiredNotes
aboutstring or nullNoThe short about line
addressstring or null, max 256 charsNoBusiness address
descriptionstring or nullNoLonger description
emailstring or nullNoContact email
verticalstring or nullNoOne of OTHER, AUTO, BEAUTY, APPAREL, EDU, ENTERTAIN, EVENT_PLAN, FINANCE, GROCERY, GOVT, HOTEL, HEALTH, NONPROFIT, PROF_SERVICES, RETAIL, TRAVEL, RESTAURANT, ALCOHOL, ONLINE_GAMBLING, PHYSICAL_GAMBLING, OTC_DRUGS. Case-insensitive. UNDEFINED and NOT_A_BIZ are rejected
websitesstring[] or nullNoWebsite URLs
profile_picture_handlestring or nullNoAn upload handle for the new picture. Get one by uploading a JPEG or PNG to POST /media/resumable. Passing a picture URL here does not work

WhatsApp validates the other lengths itself, and its rejection comes back as 422.

curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/business_profile \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "about": "Fresh coffee, delivered.",
    "vertical": "RETAIL",
    "websites": ["https://acme.example"]
  }'

Returns the profile object as WhatsApp reports it after the update.

Blocked users

A blocked user cannot message the number, and the number cannot message them. WhatsApp only accepts a block for a user who messaged the number in the last 24 hours, and a number can hold up to 64,000 blocked users.

List blocked users

GET /api/v1/whatsapp/phone_numbers/{phone_id}/blocked_users · scope whatsapp:read

ParamTypeDefaultNotes
limitinteger, 1 to 1000WhatsApp's defaultPage size
afterstring, max 1024Cursor from a previous page's after
beforestring, max 1024Cursor from a previous page's before
curl "https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/blocked_users?limit=100" \
  -H "Authorization: Bearer cm_your_api_key"

Response (200 OK)

{
  "data": [{ "wa_id": "919000000000" }, { "wa_id": "919111111111" }],
  "after": "MjQZD",
  "before": null
}

Each entry carries only the wa_id; WhatsApp does not report when or by whom a user was blocked.

Block users

POST /api/v1/whatsapp/phone_numbers/{phone_id}/blocked_users · scope whatsapp:write

FieldTypeRequiredNotes
usersstring[], 1 to 1000 itemsYesPhone numbers in international format
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/blocked_users \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "users": ["+919000000000", "+919222222222"] }'

Response (200 OK)

A batch can partly succeed, so the response always lists both outcomes:

{
  "blocked": [{ "input": "+919000000000", "wa_id": "919000000000" }],
  "failed": [
    {
      "input": "+919222222222",
      "wa_id": "919222222222",
      "reason": "This user has not messaged you in the last 24 hours, so Meta will not accept a block for them yet."
    }
  ]
}
CodeMeaning
400The business number tried to block itself
409The blocklist is full (64,000), or another change to it is still in progress
429Too many blocklist requests for this number. Wait, then retry

Unblock users

DELETE /api/v1/whatsapp/phone_numbers/{phone_id}/blocked_users · scope whatsapp:write

A DELETE with a JSON body, same shape as block.

curl -X DELETE https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/blocked_users \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "users": ["+919000000000"] }'
{
  "unblocked": [{ "input": "+919000000000", "wa_id": "919000000000" }],
  "failed": []
}

A QR code and its wa.me short link open a chat with your number with a message already typed. Use them on packaging, posters and receipts.

The QR code object

FieldTypeNotes
codestringThe code's id
prefilled_messagestringThe message pre-typed for the customer
deep_link_urlstringThe short link, for example https://wa.me/message/4O4YGZEG3RIVE1
qr_image_urlstring, nullableThe QR image. Returned only on create; null on list, get and update. Keep it from the create response

List QR codes

GET /api/v1/whatsapp/phone_numbers/{phone_id}/qr_codes · scope whatsapp:read

curl https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/qr_codes \
  -H "Authorization: Bearer cm_your_api_key"

Returns an array of QR code objects.

Create a QR code

POST /api/v1/whatsapp/phone_numbers/{phone_id}/qr_codes · scope whatsapp:write

FieldTypeRequiredNotes
prefilled_messagestring, 1 to 140 charsYesThe message pre-typed for the customer
generate_qr_imagestringNoSVG (default) or PNG. Case-insensitive
curl -X POST https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/qr_codes \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "prefilled_message": "Hi, I want to reorder my coffee", "generate_qr_image": "PNG" }'

Response (200 OK)

{
  "code": "4O4YGZEG3RIVE1",
  "prefilled_message": "Hi, I want to reorder my coffee",
  "deep_link_url": "https://wa.me/message/4O4YGZEG3RIVE1",
  "qr_image_url": "https://scontent.xx.fbcdn.net/..."
}

Get one QR code

GET /api/v1/whatsapp/phone_numbers/{phone_id}/qr_codes/{code} · scope whatsapp:read

Returns one QR code object, with qr_image_url as null. 404 if WhatsApp does not report that code on the number.

Update a QR code

PATCH /api/v1/whatsapp/phone_numbers/{phone_id}/qr_codes/{code} · scope whatsapp:write

Changes only the prefilled message. The code and deep_link_url stay the same, so anything already printed keeps working.

FieldTypeRequiredNotes
prefilled_messagestring, 1 to 140 charsYesThe new message
curl -X PATCH https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/qr_codes/4O4YGZEG3RIVE1 \
  -H "Authorization: Bearer cm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{ "prefilled_message": "Hi, I want to track my order" }'

Returns the updated QR code object.

Delete a QR code

DELETE /api/v1/whatsapp/phone_numbers/{phone_id}/qr_codes/{code} · scope whatsapp:write

curl -X DELETE https://api.callmissed.com/api/v1/whatsapp/phone_numbers/9c2b7e30-1d8a-4c5f-9b3d-2f4a6e8b1c2d/qr_codes/4O4YGZEG3RIVE1 \
  -H "Authorization: Bearer cm_your_api_key"
{ "ok": true }

The short link stops working once the code is deleted.