Zernio
Zernio
PlatformsMeta Ads

Build

CampaignsAd SetsCreativesCreative LibraryPreviews

Target

TargetingCustom Audiences

Ad types

Boost a PostCreative TestingConversion CampaignsCatalog AdsMessaging & Call AdsClick-to-WhatsApp AdsLead Gen FormsReach & Frequency

Measure

InsightsMeta PixelsConversions APIAd URL Tracking Tags

Operate

Duplicate & LifecycleAccount & Ops ReadsAd LibraryAd CommentsMedia & Limits
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Meta Ads

Lead Gen Forms

Create and manage Meta lead generation forms


Lead Gen Forms

Create native Meta Lead Gen (Instant) Forms, attach them to ads, and receive submitted leads in real time. The full flow:

  1. Create a form on a connected Facebook account with POST /v1/ads/lead-forms. Forms are Page-scoped (Instagram lead ads use the linked Page's form under the hood).
  2. Attach it to an ad by setting goal: "lead_generation" and leadGenFormId on POST /v1/ads/create (standalone) or POST /v1/ads/boost (boost an existing post). The ad set's lead optimization and promoted Page are derived automatically, no destination URL is needed.
  3. Receive leads in real time via the lead.received webhook, or pull them with GET /v1/ads/lead-forms/{formId}/leads.

One-time setup: your Facebook Page must accept Facebook's Lead Generation Terms of Service before lead ads can run. If ad creation returns Meta error subcode 1815089 ("Terms of Service Not Accepted"), accept them once at https://www.facebook.com/ads/leadgen/tos/?page_id=YOUR_PAGE_ID. Creating forms and reading leads works without it, only running ads requires it.

The form content now rides on platformSpecificData. The same /v1/ads/lead-forms endpoints serve Meta and LinkedIn, with the platform selected by accountId and the platform-shaped form content (questions, thank-you screen, context card, ...) inside platformSpecificData. The top-level Meta fields shown below (questions, thankYou*, contextCard, ...) are deprecated but still accepted when platformSpecificData is absent — existing integrations keep working. Mixing both shapes in one request returns a 400, and so does an unknown key inside platformSpecificData.

Create a form, then a lead ad

Prefilled question types (EMAIL, PHONE, FULL_NAME, FIRST_NAME, LAST_NAME, …) auto-generate their label and key, send only { "type": "..." }. CUSTOM questions require key, label, and (for choice questions) options.

New-shape example (the deprecated flat shape is the same fields at the top level):

{
  "accountId": "FACEBOOK_ACCOUNT_ID",
  "name": "Spring promo",
  "privacyPolicyUrl": "https://example.com/privacy",
  "platformSpecificData": {
    "questions": [
      { "type": "EMAIL" },
      { "type": "FULL_NAME" },
      { "type": "CUSTOM", "key": "budget", "label": "Monthly budget?", "options": [
        { "key": "low", "value": "Under $1k" },
        { "key": "high", "value": "$1k+" }
      ] }
    ]
  }
}
// 1. Create the form
const { form } = await zernio.leadgen.createLeadForm({ body: {
  accountId: 'FACEBOOK_ACCOUNT_ID',
  name: 'Spring promo',
  questions: [
    { type: 'EMAIL' },
    { type: 'FULL_NAME' },
    { type: 'CUSTOM', key: 'budget', label: 'Monthly budget?', options: [
      { key: 'low', value: 'Under $1k' },
      { key: 'high', value: '$1k+' },
    ] },
  ],
  privacyPolicyUrl: 'https://example.com/privacy',
} });

// 2. Create an ad that opens the form (no linkUrl needed)
const { ad } = await zernio.adcampaigns.createStandaloneAd({ body: {
  accountId: 'FACEBOOK_ACCOUNT_ID',
  adAccountId: 'act_123',
  name: 'Spring promo lead ad',
  goal: 'lead_generation',
  leadGenFormId: form.id,
  budgetAmount: 10,
  budgetType: 'daily',
  headline: 'Get a quote',
  body: 'Tell us about your project',
  callToAction: 'SIGN_UP',
  imageUrl: 'https://example.com/creative.jpg',
} });

Receiving leads

The best way to capture leads is the lead.received webhook, fired the moment a lead is submitted. The payload carries lead.fields (the question-key to answer map) plus formId / adId provenance. You can also poll for them:

const { leads } = await zernio.leadgen.listFormLeads({
  path: { formId: 'FORM_ID' },
  query: { accountId: 'FACEBOOK_ACCOUNT_ID', limit: 50 },
});
for (const lead of leads) console.log(lead.fields);

GET /v1/ads/leads is the cross-form view of the same data: every lead the connected account has captured, filterable by formId and since, for feeding a CRM without iterating forms.

Test leads

POST /v1/ads/lead-forms/{formId}/test-leads creates a synthetic lead on the form so you can exercise your lead.received webhook handler and field mapping end-to-end before spending. The body requires accountId and fieldData, an array of { name, values[] } entries (at least one) matching the form's questions, for example { "accountId": "...", "fieldData": [{ "name": "email", "values": ["test@example.com"] }] }. Meta allows one pending test lead per form: delete or consume it before creating another.

To attach a form when boosting an existing post, pass the same leadGenFormId (and goal: "lead_generation") to POST /v1/ads/boost. To retire a form, DELETE /v1/ads/lead-forms/{formId} (Meta archives it, there is no hard delete).

LinkedIn lead forms and lead retrieval share these endpoints (selected by accountId, with the LinkedIn-shaped platformSpecificData); they're documented on LinkedIn Ads.

Was this page helpful?

Click-to-WhatsApp Ads

Create ads that open a WhatsApp conversation

Reach & Frequency

Quote, reserve and buy fixed-price reserved Meta campaigns

On this page

Lead Gen FormsCreate a form, then a lead adReceiving leadsTest leads