Prerequisites, Embedded Signup, PIN registration, number states, and why an integration should branch on one flag.
There is no /api/v2 endpoint for connecting a number. Connecting, reconnecting, registering, and disconnecting all happen in the Ghala dashboard.
That is deliberate rather than an omission: onboarding involves a Meta-hosted popup, a Meta login, and in some cases an OTP sent to a physical handset. None of it can be automated from a server without a person present.
What this page gives you is the shape of the process, so you know what your client is going through, what can go wrong, and what state to wait for before your integration starts sending.
Before anybody clicks anything:
| Requirement | Notes |
|---|---|
| A Meta Business Portfolio | Formerly "Business Manager". The container that owns the WhatsApp Business Account |
| A WhatsApp Business Account (WABA) | Created during Embedded Signup if you do not have one |
| A phone number you control | Able to receive an SMS or voice OTP during registration |
| The number is not already registered to another WhatsApp account you intend to keep | A number can only be live on one WhatsApp account at a time |
| A Facebook account with admin rights on the portfolio | The person completing the flow needs permission to grant access |
| A Ghala team | The number is connected into a team, and that team's plan governs API access |
If the number is currently in use on the WhatsApp Business App, read the coexistence section below before you start.
Dashboard → Add WhatsApp Account, or the account switcher.
Ghala opens Meta's Embedded Signup popup. Everything inside that popup is Meta's: the login, the portfolio picker, the WABA and number selection, and the permission grant. Ghala never sees the client's Facebook password.
The steps a client sees:
When the flow finishes, Meta hands back a short-lived authorization code. Ghala exchanges it for the number's access token, verifies which WABA the token actually belongs to, and discovers the phone number if the popup did not report it. The token is derived from the grant, not from anything the browser claims, so a client cannot connect a number they do not control.
The popup can also finish in a WABA-only variant, where a portfolio and WABA are authorized but no number is selected yet. That leaves the account connected but not sendable, which is what the state fields below are for.
WhatsApp numbers use a six-digit two-step verification PIN. Ghala sets one during onboarding and stores it, because the number cannot be registered without it and the client will need it again for WhatsApp Manager.
You can read it at any time from the number's entry in the dashboard, as an explicit reveal action. Withholding it would make Ghala a lock-in point: the PIN is what a merchant needs to take their number elsewhere, so it stays theirs.
Registration is the step that makes a number able to send. If it did not complete during signup, the number's entry offers a retry, which takes the PIN and nothing else. The phone number id and access token come from the stored credential, so nobody can register a number they do not own by supplying their own ids. Retrying is safe: a number that is already live returns success unchanged.
This is the part that goes wrong most often, and the rule is simple:
Registration applies to a new WhatsApp account only. A number already live on the WhatsApp Business App is already registered with Meta, and running registration against it is wrong.
Ghala records how a number arrived as its onboarding method:
| Onboarding method | Meaning | Registration |
|---|---|---|
NEW_WHATSAPP_ACCOUNT |
A number new to the WhatsApp Business Platform | Required, and retryable |
EXISTING_WHATSAPP_BUSINESS_APP |
Migrated from the WhatsApp Business App | Already registered with Meta; do not run it |
UNKNOWN |
Method could not be determined | Check the number's status before acting |
Practical consequences for a number coming off the WhatsApp Business App:
A connected number carries several state fields, and the mistake to avoid is branching on the wrong one. A number can have a valid token, a real WABA id, and a phone number id, and still be unable to send a single message.
| Field | What it tells you |
|---|---|
live |
Whether the number can actually send. The one flag to branch on |
connection_status |
Whether the credential is connected, and its current state |
registration_status |
How far registration with Meta has got |
onboarding_method |
New account, migrated from the Business App, or unknown |
action_required |
What the merchant must do next, when something is blocking |
registered_at |
When registration completed |
registration_attempted_at |
When it was last tried |
registration_error |
Why the last registration attempt failed |
last_status_synced_at |
When Ghala last reconciled against Meta |
disconnected_at |
Set when the number was disconnected |
account_blocked_at / account_block_reason |
Set when Meta has blocked the account |
template_sync_error |
Why templates could not be pulled from Meta |
error_message |
The current problem, in words |
Branch on live. Every other combination of ids and tokens can look healthy while the number is mute. If your integration has a "is this tenant ready" check, live is it.
The dashboard's status check reconciles against Meta before reporting, and this matters more than it sounds. Ghala's record can be stale in the dangerous direction: a registration Meta accepted but Ghala failed to record leaves a number that is live at Meta and pending in Ghala. Re-syncing resolves that rather than re-running registration.
| Symptom | Usual cause | Fix |
|---|---|---|
| Popup closes with nothing connected | The client cancelled, or lacks admin rights on the portfolio | Retry with an account that has admin rights |
Connected, but live is false |
Registration did not complete | Retry registration with the PIN |
| Registration fails repeatedly | The number already has a different two-step PIN set | Reset the PIN in WhatsApp Manager, then retry |
| Registration fails on a migrated number | Registration was run on a number already registered via the Business App | Do not register; it is already registered |
| Number connected, no templates appear | Template sync from Meta failed | Check template_sync_error; re-sync from the dashboard |
| Display name shows as the raw number | Meta has not approved the display name yet | Wait for Meta's review; it is Meta's process, not Ghala's |
Everything looks right, sends return 402 |
The team's plan lacks API access | Upgrade under Settings → Billing |
Everything looks right, sends return 401 |
The token in your integration is stale | Re-copy it; a reconnect invalidates the old one |
Business display name is reviewed by Meta, not Ghala. A rejected name is resubmitted in WhatsApp Manager. Until it is approved, customers see the number rather than the name.
Reconnecting runs Embedded Signup again against a number that is already connected, and refreshes its credentials from the new grant.
Reach for it when the token has been leaked, when Meta's grant has been revoked or has otherwise stopped working, or when permissions changed on the portfolio.
Reconnecting issues a new access token and invalidates the old one immediately. There is no overlap window. Every integration holding the previous token starts returning
401on its next call, so update your stored secret as part of the same task.
Disconnecting stops the number routing to Ghala: no inbox, no AI agent, no order capture, and no API sends.
It also frees the number to be claimed by another team, so it is not a quiet operation and it is recorded in the audit log. Disconnect when you mean to hand the number back, not as a troubleshooting step.
Before your code sends its first message for a new tenant:
liveGET /api/v2/templates?limit=1 returns 200 — proof of authentication that messages nobodysendable, so you can open a conversation outside the 24-hour window