GET /v1/leads.
Endpoints
pageLinkId is the id of the link (linked[].pageLinkId), not the Facebook Page id.
Before you link: sharing and ownership
There is no Meta login step. On Meta’s side, the advertiser:- shares the Page with the Pilot Status business portfolio — the
partnerBusinessIdthatGET /v1/lead-pagesreturns — in Meta Business Manager; - gives the Pilot Status system user the Page tasks it needs.
candidates[].missingTaskslists what is still missing:MODERATE,MANAGE_LEADS, orPAGE_ACCESSwhen the Page was not assigned to the system user at all. An empty list means ready;nullmeans Meta could not be asked.
candidates is empty and eligibilityBlocker is NO_OFFICIAL_NUMBER. The leads can then
go to any number of the workspace, official or not.
Credentials and permissions
- OAuth/MCP tokens need
integrations:manage(workspace ADMIN or OWNER) on every endpoint, reads included — ANALYST and AGENT are refused with403 PERMISSION_DENIED. A classicps_key has no role and passes by its scope. - Scope: a number-scoped key, or an account-wide credential with the
x-whatsapp-number-idheader, sees and changes only the links of that number. An account-wide credential without the header sees the whole workspace and names the number in the body. A link on a number outside the credential’s scope answers403 NUMBER_NOT_IN_GRANT.
GET /v1/lead-pages
subscribedAt: null means Meta is not sending that Page’s leads, whatever else the link
says. subscriptionError gives the reason: META_PERMISSION_MISSING, PAGE_ACCESS_MISSING,
META_NOT_FOUND, META_UNAVAILABLE, META_NOT_CONFIRMED, META_ERROR, or — when the Page stopped being
eligible — PAGE_NOT_SHARED, PAGE_BUSINESS_MISMATCH, NO_OFFICIAL_NUMBER. Fix it on Meta’s side
and resync the link (below).
POST /v1/lead-pages
pageIdis the numeric Facebook Page id.whatsappNumberIdmay be left out only when the credential is bound to one number. Any other field is refused with400 UNKNOWN_FIELDS.- Ownership and the Page tasks are checked before anything is written:
409 PAGE_NOT_ELIGIBLE(withreasonwhen known; without one when another workspace already linked the Page),409 PAGE_MISSING_PERMISSION(withmissingTasks),409 PAGE_ALREADY_LINKED(with the existingpageLinkId). - On success (
201 { "link": { … } }) Pilot Status subscribes to the Page’s leads and starts pulling its last 90 days of leads in the background. If Meta refuses the subscription, the link is still created andsubscriptionErrorsays why.
PATCH /v1/lead-pages/{pageLinkId}
Moves the link to another number of the workspace. The body is { "whatsappNumberId": "…" }.
Only new leads follow; leads already captured stay on the number they arrived on.
When the new number sends a different kind of message — an official number sends templates, an
unofficial one free text — or sits on another WABA, every automatic message of the link’s forms
is switched off, and the answer says "autoSendDisabled": true. Review the forms before turning
it back on.
DELETE /v1/lead-pages/{pageLinkId}
Pilot Status also unsubscribes from the Page’s leads on Meta. If Meta fails, the unlink goes
through anyway and no further lead from that Page is stored.
POST /v1/lead-pages/{pageLinkId}/resync
Pulls the Page’s last 90 days of leads again — already-stored leads are not duplicated — and,
when the link is not subscribed, retries the subscription. It takes no body and answers 202:
subscribedAt and subscriptionError appear only when this call retried the subscription. The
pull itself runs in the background and can take minutes.
- One resync per link every 10 minutes. Inside that window the answer is
429 RESYNC_COOLDOWNwithretryAfterSeconds. If the wait cannot be checked, the answer is503 RESYNC_UNAVAILABLE, never an unbounded resync. - Ownership is checked again. A Page that is no longer eligible is flagged on the link
(
subscriptionError) and answers409 PAGE_NOT_ELIGIBLEwithreason.
GET /v1/lead-pages/{pageLinkId}/forms
The Page’s Instant Forms, read live from Meta, each with its questions, its consentCheckboxes
and the configuration stored in Pilot Status (config, or null when never configured). The
answer also carries numberIsOfficial and, for an official number, the approved templates the
link’s number can send automatically (templates, each { id, name, variables }; empty on an
unofficial number).
consentAvailable: false— the form’s checkboxes could not be read. The list is unknown, not empty.formsTruncated: true— the Page has more forms than Pilot Status read.
PUT /v1/lead-pages/{pageLinkId}/forms/{formId}
Creates or replaces one form’s configuration. Send the whole object:
The message rules apply only when
autoSendEnabled is true, so you can save the consent
checkbox and a draft first. The answer is 200 { "config": { … } }.
Errors
The refusals of these endpoints carry
{ "error": "<English> | <Português>", "code": "…" }.