Lead Gen Forms
Create LinkedIn Lead Gen Forms with POST /v1/ads/lead-forms and pull their responses with GET /v1/ads/leads.
When you finish this page you have a LinkedIn Lead Gen Form and a way to pull its responses. LinkedIn forms share the /v1/ads/lead-forms endpoints with Meta: accountId selects the platform and the LinkedIn-shaped content goes inside platformSpecificData. LinkedIn forms are owned by the ad account's Company Page, so the calls also take adAccountId.
Create a form
Call POST /v1/ads/lead-forms with accountId, name, privacyPolicyUrl and a platformSpecificData carrying adAccountId, headline, description and at least one question. Every question needs kind, name and question; a multipleChoice question also needs choices.
import Zernio from '@zernio/node';
const zernio = new Zernio();
const { data: created } = await zernio.leadgen.createLeadForm({
body: {
accountId: '66b2e19d8c3f5a7e9d0b1c2d',
name: 'Q3 Whitepaper form',
privacyPolicyUrl: 'https://example.com/privacy',
platformSpecificData: {
adAccountId: '517258773',
headline: 'Get the whitepaper',
description: 'Fill in your details and we will send it over.',
state: 'PUBLISHED',
questions: [
{ kind: 'text', name: 'company', question: 'Company name', maxResponseLength: 120 },
{ kind: 'multipleChoice', name: 'size', question: 'Team size',
choices: [{ id: 1, text: '1 to 10' }, { id: 2, text: '11 to 50' }] }
],
consents: [{ description: 'I agree to be contacted', required: true }]
}
}
});
console.log(created.form.id);Response (200):
{
"status": "success",
"form": { "id": "4210986", "name": "Q3 Whitepaper form" }
}Pass form.id as leadGenFormId on a goal: "lead_generation" ad (Create ads). The create is not idempotent: a retry creates a second form.
- Question kinds are
textandmultipleChoiceonly. LinkedIn's API does not expose profile-prefilled fields (EMAIL, FIRST_NAME, ...); those exist in Campaign Manager's UI only. stateisDRAFT(default) orPUBLISHED.consents[]entries are{ description, required? }; Zernio maps them to LinkedIn's wire shape and assigns ids.maxResponseLengthdefaults to 300 on LinkedIn's side.
List, get and archive
GET /v1/ads/lead-forms?accountId=&adAccountId=lists the forms owned by the Company Page:{ id, name, state, headline, createdTime }.GET /v1/ads/lead-forms/{formId}?accountId=returns the full form.DELETE /v1/ads/lead-forms/{formId}?accountId=archives the form (state: ARCHIVED); LinkedIn has no hard delete.
Retrieve leads
Call GET /v1/ads/leads with accountId and adAccountId, and formId to narrow to one form. This is the only lead read LinkedIn has: the per-form GET /v1/ads/lead-forms/{formId}/leads and test-leads endpoints on the Meta lead-forms page are Meta-only, because LinkedIn exposes no per-form finder.
const { data: page } = await zernio.leadgen.listLeads({
query: { accountId: '66b2e19d8c3f5a7e9d0b1c2d', adAccountId: '517258773', formId: created.form.id, limit: 50 }
});
console.log(page.leads[0].fields);Response (200):
{
"status": "success",
"leads": [
{
"id": "66f1a2b3c4d5e6f7a8b9c0d1",
"leadgenId": "9021734",
"formId": "4210986",
"formName": "Q3 Whitepaper form",
"campaignId": "810456563",
"createdTime": "2027-01-06T09:12:44.000Z",
"fields": { "company": "Acme", "size": "11 to 50" }
}
],
"pagination": { "hasMore": false, "cursor": null }
}fields maps each question name to its answer; multiple-choice values are the option labels. campaignId is the LinkedIn Campaign, which is platformAdSetId on GET /v1/ads.
- Leads are fetched live from LinkedIn; there is no LinkedIn lead webhook. Poll on your own schedule.
- LinkedIn retains responses for 90 days. Pull them out regularly; anything older is gone on LinkedIn's side.
sinceis Unix seconds;cursoris the numeric offset frompagination.cursor.
If it fails
A 400 with code ads_connection_required on GET /v1/ads/leads means the connection predates the r_marketing_leadgen_automation scope: LinkedIn's 403 is turned into an actionable reconnect prompt. Form create, list and archive work without the scope; reading responses does not.
{
"error": "Reading LinkedIn lead responses needs the r_marketing_leadgen_automation permission. Reconnect this LinkedIn account to grant it.",
"type": "invalid_request_error",
"code": "ads_connection_required",
"param": "accountId"
}One pass through the LinkedIn connect flow fixes it (scopes).
Related
- Create ads: attach the form with
goal: "lead_generation"andleadGenFormId. - Meta Ads lead forms: the Meta shape of the same endpoints.
- Create a lead form and List submitted leads: every field.