Skip to main content
When someone submits a Meta Lead Ads Instant Form (Facebook or Instagram) on a Facebook Page that is linked to one of your WhatsApp numbers in the Pilot Status dashboard, Pilot Status stores the lead under that number. These two endpoints read those leads back: one lists them, one returns a single lead.

Endpoints

GET https://pilotstatus.com.br/v1/leads GET https://pilotstatus.com.br/v1/leads/{id}
Both act on one number: use a number-scoped API key (ps_*) in the x-api-key header, or an account-wide key that names the number in the x-whatsapp-number-id header. An account-wide key without that header gets 403 TENANT_SCOPE_NOT_ALLOWED.
A lead belongs to the number its Page is linked to, exactly like a conversation does. You only ever see the leads of the number the request acts on — never the leads of your other numbers. OAuth / MCP tokens also need the chat:read permission in the workspace: a lead is a person’s contact data, so the ANALYST role is refused with 403 PERMISSION_DENIED. A classic ps_ key is not affected by roles. The same data is available to AI agents through the leads_list and leads_get tools of the MCP server. To be told about a new lead as it arrives instead of polling, subscribe a webhook to the lead.received event. It is opt-in: a webhook subscribed to "*" does not receive it, so list "lead.received" by name.

Two ids: id and leadgenId

consentGiven has three states

null means unknown — never read it as a refusal, nor as consent.
The value is decided when the lead is stored, from the checkbox configured for the form at that moment. Configuring the checkbox later does not change leads that were already stored.

GET /v1/leads

Newest first by createdAt (ties broken by id, descending). Erased leads are never listed and never counted.

Query parameters

string
Restrict to a single Instant Form id.
string
Restrict to a single ad id.
string
Restrict to a single Facebook Page id.
string
ISO 8601 datetime. Leads whose createdAt is on or after this instant.
string
ISO 8601 datetime. Leads whose createdAt is on or before this instant.
integer
default:"1"
Page number (≥ 1). A missing, non-numeric or smaller value is read as 1.
integer
default:"30"
Results per page (1–100). A larger value is capped at 100.
The date filters apply to createdAt — when the person submitted the form on Meta — and not to when Pilot Status stored the lead. A lead imported afterwards (source: "backfill") keeps the date the person submitted it.

Pagination

The response carries total (every lead that matches the filter), page, pageSize and totalPages. Report counts from total, not from the length of leads. Paging stops at 10,000 rows: when page × pageSize passes it, the request fails with 400 INVALID_PAGINATION. Narrow the window with startDate/endDate instead of paging further.

Example

GET /v1/leads/{id}

Returns one lead of the number by its Pilot Status id, wrapped as { "lead": { … } }, with the same fields, the same privacy rules and the same notice as the list.
string
required
The Pilot Status lead id — the id field returned by GET /v1/leads, not Meta’s leadgenId.
A lead of another number, of another account, or one that was erased answers 404 LEAD_NOT_FOUND — the same answer as an id that never existed.

The lead object

Privacy (PII) mode effect

A redacted lead still exists and still counts: it keeps its ids, its attribution (page, form, ad and the resolved ad names — the advertiser’s own labels, not personal data) and its status fields. Only fullName, email and phone come back null and fields comes back empty, with redacted: true. That split keeps lead counting and attribution working on a RELAY_ONLY number instead of returning nothing. A lead that was stored redacted (because the number was RELAY_ONLY when it arrived) stays redacted even after the number moves to another mode — the personal data was never kept.
If the number’s privacy mode cannot be read, leads come back unredacted. The check fails open: when Pilot Status cannot read the number’s PII mode while answering (a database error, for example), the request is not refused — every lead whose personal data is stored comes back with fullName, email, phone and fields, and without notice, even on a RELAY_ONLY number (for example, leads captured before the number was switched to RELAY_ONLY) and even past a STORE_X_DAYS window. Only a lead stored redacted stays redacted, because there is nothing to return. This is deliberate: a failed check never makes your leads disappear. If you rely on the redaction downstream, check redacted per lead rather than assuming it from the number’s mode.

Errors