Three WhatsApp Cloud API gotchas that cost me weekend

Building Autopilot meant going deep on Meta's WhatsApp Cloud API — and it's a genuinely solid platform once it's working. Getting it working is where the real documentation gap is. Here are three things that cost real hours.

1. A connected number isn't a registered number

You can walk a business through Embedded Signup, get a shiny new phone number attached to their WhatsApp Business Account, and send your first message — only to get this back:

{
  "error": {
    "message": "(#133010) Account not registered",
    "code": 133010,
    "type": "OAuthException"
  }
}

Connecting a number to a WABA and registering it for the Cloud API are two separate steps. The fix is a second call most tutorials skip:

await fetch(`https://graph.facebook.com/v21.0/${phoneNumberId}/register`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ messaging_product: 'whatsapp', pin: '123456' }),
});

Do this once, right after Embedded Signup completes, and the error disappears.

2. debug_token knows things /me/businesses doesn't

If you're using Embedded Signup with a config_id, the resulting token is scoped narrowly — calling /me/businesses to find the user's WhatsApp Business Account often fails with a plain (#100) Missing Permission, even though the token clearly can send messages.

The actual WABA ID is sitting in the token's own granular scopes the whole time:

const res = await fetch(
  `https://graph.facebook.com/v21.0/debug_token?input_token=${token}&access_token=${appId}|${appSecret}`
);
const { data } = await res.json();
const wabaIds = data.granular_scopes
  ?.find(s => s.scope === 'whatsapp_business_management')
  ?.target_ids ?? [];

No business_management permission required. This one detail replaces an entire fallback chain of business-walking API calls.

3. "Authorization Error" can mean "wrong scope," not "wrong token"

A token that successfully reads phone numbers and manages a WABA can still fail to send a message with a bare:

{ "error": { "message": "Authorization Error", "code": 100 } }

That's not a bad token — whatsapp_business_management (manage) and whatsapp_business_messaging (send) are separate permissions, and it's easy to generate a token with only the first. If sending fails with code 100 and everything else about the token checks out, check the granted scopes before you check anything else.

None of these are hard once you know them. All three cost me actual weekend hours before I did.