Link a Lead Ads Page
Links one Facebook Page to one WhatsApp number of the workspace, subscribes Pilot Status to the Page’s leads and starts pulling its last 90 days of leads in the background.
Body: pageId (the numeric Facebook Page id) and whatsappNumberId. whatsappNumberId may be omitted only when the credential is bound to one number (a number-scoped key, or x-whatsapp-number-id); a number outside the credential’s scope is 403 NUMBER_NOT_IN_GRANT. Any other field is refused with 400 UNKNOWN_FIELDS.
Ownership and permissions are checked before anything is written: 409 PAGE_NOT_ELIGIBLE (with reason when known: NO_OFFICIAL_NUMBER, PAGE_NOT_SHARED, PAGE_BUSINESS_MISMATCH; no reason when another workspace already linked it), 409 PAGE_MISSING_PERMISSION (with missingTasks), 409 PAGE_ALREADY_LINKED (with the existing pageLinkId). If Meta refuses the subscription, the link is still created and the reason is returned in subscriptionError — resync retries it.
OAuth/MCP tokens need integrations:manage (workspace ADMIN or OWNER) on every verb, reads included. Scope: a number-scoped key, or an account-wide credential with x-whatsapp-number-id, acts only on that number’s links; an account-wide credential without the header sees the whole workspace.
curl --request POST \
--url https://pilotstatus.com.br/v1/lead-pages \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"pageId": "109876543210987",
"whatsappNumberId": "num_01HZX..."
}
'import requests
url = "https://pilotstatus.com.br/v1/lead-pages"
payload = {
"pageId": "109876543210987",
"whatsappNumberId": "num_01HZX..."
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({pageId: '109876543210987', whatsappNumberId: 'num_01HZX...'})
};
fetch('https://pilotstatus.com.br/v1/lead-pages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pilotstatus.com.br/v1/lead-pages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'pageId' => '109876543210987',
'whatsappNumberId' => 'num_01HZX...'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/lead-pages"
payload := strings.NewReader("{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pilotstatus.com.br/v1/lead-pages")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/lead-pages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}"
response = http.request(request)
puts response.read_body{
"link": {
"pageLinkId": "cmgpl0001ab12cd34ef56",
"pageId": "109876543210987",
"pageName": "MM Design Outlet",
"whatsappNumberId": "num_01HZX...",
"subscribedAt": "2026-10-06T10:15:00.000Z",
"subscriptionError": null,
"linkedAt": "2026-10-06T10:14:58.000Z",
"leadsCount": 0
}
}{
"error": "Validation failed | Falha na validação",
"code": "VALIDATION_FAILED"
}{
"error": "Unauthorized"
}{
"error": "This credential is not granted access to that WhatsApp number | Esta credencial não tem acesso a esse número de WhatsApp",
"code": "NUMBER_NOT_IN_GRANT"
}{
"error": "WhatsApp number not found | Número de WhatsApp não encontrado",
"code": "NUMBER_NOT_FOUND"
}{
"error": "Pilot Status does not have the required permissions on this Page yet. | A Pilot Status ainda não tem as permissões necessárias nesta página.",
"code": "PAGE_MISSING_PERMISSION",
"missingTasks": [
"MANAGE_LEADS"
]
}{
"error": "Internal server error | Erro interno do servidor",
"code": "INTERNAL_ERROR"
}{
"error": "Could not reach Meta right now. Try again. | Não foi possível consultar a Meta agora. Tente novamente.",
"code": "LEADS_LOOKUP_UNAVAILABLE"
}{
"error": "Meta lead capture is not configured on this installation. | Captura de leads da Meta não configurada nesta instalação.",
"code": "LEADS_NOT_CONFIGURED"
}Authorizations
Your ps_ API key
Headers
Narrows an account-wide credential to one number (its id or instance id from GET /v1/numbers). Without it, an account-wide credential sees the whole workspace; a number-scoped key always sees only its own number.
Body
Response
Page linked
Was this page helpful?
curl --request POST \
--url https://pilotstatus.com.br/v1/lead-pages \
--header 'Content-Type: application/json' \
--header 'x-api-key: <api-key>' \
--data '
{
"pageId": "109876543210987",
"whatsappNumberId": "num_01HZX..."
}
'import requests
url = "https://pilotstatus.com.br/v1/lead-pages"
payload = {
"pageId": "109876543210987",
"whatsappNumberId": "num_01HZX..."
}
headers = {
"x-api-key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'x-api-key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({pageId: '109876543210987', whatsappNumberId: 'num_01HZX...'})
};
fetch('https://pilotstatus.com.br/v1/lead-pages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://pilotstatus.com.br/v1/lead-pages",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'pageId' => '109876543210987',
'whatsappNumberId' => 'num_01HZX...'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"x-api-key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://pilotstatus.com.br/v1/lead-pages"
payload := strings.NewReader("{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("x-api-key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://pilotstatus.com.br/v1/lead-pages")
.header("x-api-key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://pilotstatus.com.br/v1/lead-pages")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["x-api-key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"pageId\": \"109876543210987\",\n \"whatsappNumberId\": \"num_01HZX...\"\n}"
response = http.request(request)
puts response.read_body{
"link": {
"pageLinkId": "cmgpl0001ab12cd34ef56",
"pageId": "109876543210987",
"pageName": "MM Design Outlet",
"whatsappNumberId": "num_01HZX...",
"subscribedAt": "2026-10-06T10:15:00.000Z",
"subscriptionError": null,
"linkedAt": "2026-10-06T10:14:58.000Z",
"leadsCount": 0
}
}{
"error": "Validation failed | Falha na validação",
"code": "VALIDATION_FAILED"
}{
"error": "Unauthorized"
}{
"error": "This credential is not granted access to that WhatsApp number | Esta credencial não tem acesso a esse número de WhatsApp",
"code": "NUMBER_NOT_IN_GRANT"
}{
"error": "WhatsApp number not found | Número de WhatsApp não encontrado",
"code": "NUMBER_NOT_FOUND"
}{
"error": "Pilot Status does not have the required permissions on this Page yet. | A Pilot Status ainda não tem as permissões necessárias nesta página.",
"code": "PAGE_MISSING_PERMISSION",
"missingTasks": [
"MANAGE_LEADS"
]
}{
"error": "Internal server error | Erro interno do servidor",
"code": "INTERNAL_ERROR"
}{
"error": "Could not reach Meta right now. Try again. | Não foi possível consultar a Meta agora. Tente novamente.",
"code": "LEADS_LOOKUP_UNAVAILABLE"
}{
"error": "Meta lead capture is not configured on this installation. | Captura de leads da Meta não configurada nesta instalação.",
"code": "LEADS_NOT_CONFIGURED"
}