WhatsApp Cloud API media download fails (code 100, subcode 33) despite correct token and permissions

:bullseye: What is your goal?

Build a WhatsApp voice-message automation: receive audio via webhook, download the media, transcribe it with Whisper, and extract structured data with GPT.

:thinking: What is the problem & what have you tried?

Title: WhatsApp Cloud API media download fails (code 100, subcode 33) on test/sandbox number despite correct token and permissions

Setup: Meta app in development mode, using the auto-generated WhatsApp test number, scenario built in Make.com.

Incoming messages arrive correctly at my webhook — the payload includes a valid “type”: “audio” object with both “audio.id” and “audio.url” fields populated.

I’ve tried three separate methods to download the actual media file, and all three fail with the identical error:

  1. Direct GET request to the webhook-provided “audio.url” (lookaside.fbsbx.com…) with header “Authorization: Bearer ” → returns 404.

  2. GET request to https://graph.facebook.com/v21.0/{media-id} with the same token (the officially documented approach) → returns:
    {“error”:{“message”:“Unsupported get request. Object with ID ‘…’ does not exist, cannot be loaded due to missing permissions, or does not support this operation.”,“code”:100,“type”:“GraphMethodException”,“error_subcode”:33}}

  3. Make.com’s own official “WhatsApp Business Cloud” app, “Download a Media” module, using a freshly created OAuth connection (re-authorized with whatsapp_business_messaging + whatsapp_business_management permissions) → same error.

What I’ve already verified:

  • Token permissions confirmed via Graph API Explorer with the same token (whatsapp_business_management + whatsapp_business_messaging both present)
  • System User has “Full control” access assigned to the WhatsApp asset in Business Settings
  • phone_number_id and WABA ID match exactly between the webhook payload and the API Setup page
  • Tested with a freshly received message/media ID each time (not stale data)

Question: is there a known limitation on Meta’s auto-generated test/sandbox phone numbers regarding media downloads via the Graph API? Is there an additional setup step specific to test numbers (vs. verified production numbers) that isn’t obvious from the standard docs?

Any pointers appreciated — happy to share more details (fbtrace_id available on request).

:clipboard: Error messages or input/output bundles

{“error”:{“message”:“Unsupported get request. Object with ID ‘XXXXXXXXXX’ does not exist, cannot be loaded due to missing permissions, or does not support this operation. Please read the Graph API documentation at https://developers.facebook.com/docs/graph-api",“code”:100,“type”:“GraphMethodException”,“error_subcode”:33,“fbtrace_id”:"…”}}

Two things are going wrong at once here, and the first one hides the second.

The url field in the webhook payload is not a download link you can use. Meta includes it, but that lookaside host will not serve you the file with a Bearer token, which is why you get a 404 rather than an auth error. Ignore that field entirely. The supported path is two calls: GET graph.facebook.com/v21.0/{media-id} to get a fresh short-lived URL, then a second GET to that returned URL with the Authorization header still attached. People often drop the header on the second call because it looks like a plain CDN link, and that fails too.

Your real blocker is the second error, and code 100 with subcode 33 on an ID that plainly exists is almost always the token rather than the ID. Media IDs are scoped to the phone number that received the message, so the token has to belong to the same app and number, and it needs whatsapp_business_messaging. The temporary token shown in the WhatsApp setup panel is the usual culprit: it is tied to your user, it expires after 24 hours, and once it lapses Meta reports the object as not existing rather than telling you the token is stale. Generate a System User token with that permission and try the same media ID again before changing anything else in the scenario.

One timing detail once it works: the URL from the first call is valid for about five minutes, so fetch and store the file in the same run. Do not save that URL anywhere and fetch it later.

If a System User token still returns subcode 33 on a message your webhook just received, say so, because at that point it points at the test number rather than your setup and that is worth separating.

Thanks, that pointed me in the right direction. Generated a System User token
with whatsapp_business_messaging + whatsapp_business_management, swapped it
into the Make.com connection, and tested on a brand new message (not a replay).

The error changed but didn’t disappear:
[400] [100] Unsupported get request. Object with ID ‘{id}’ does not exist,
cannot be loaded due to missing permissions, or does not support this
operation. Code: RuntimeError

I’m testing on the free Meta test number (+1 555… format from the API
Setup Quickstart), sending from my personal WhatsApp to it. Before I go
register a real business number - is there any way to confirm the test
number is actually the cause here, short of that? Or does the “unsupported
get request” phrasing suggest something else entirely (vs. the earlier
subcode 33)?

Got a fresh media ID this time (not a replay) - sent a voice note just now,
it failed within 5 seconds with the same error pattern:

[400][100] Unsupported get request. Object with ID ‘1377992320490271’ does
not exist, cannot be loaded due to missing permissions, or does not support
this operation.

System User token still active (whatsapp_business_messaging +
whatsapp_business_management, never-expiring). This is genuinely a brand
new message on the free Meta test number, not a replay of an old one.
Sounds like this confirms the test-number/WABA mismatch you flagged?

Before I go buy a real number for this - is a verified real number actually
required, or is there any config/permission fix that would make this work
directly on the test number?

The webhook arriving with audio.id while Graph says the object does not exist is a token/number scope problem, not a Make mapping problem. You already proved the lookaside url is a dead end and a System User token still fails on a brand new media id.

The check I would run next, before buying a number: in Graph API Explorer, using that same System User token, GET the test phone number node and GET the WABA. Confirm the media id’s phone_number_id in the webhook matches the phone_number_id that token can read. If the token can see the number but not the media, the sandbox number is not granting media GET. That is the evidence that a real WABA number is required.

If those two GETs fail too, the System User is still not on the WhatsApp asset the webhook is using, even if Business Settings looks right.

What would settle it: the webhook phone_number_id, the phone_number_id returned by the token, and the raw Graph body for GET /{media-id} on a message less than a minute old. If the two phone ids differ, it is not a Make issue.