Lead Gen Forms
Create LinkedIn Lead Gen Forms and pull lead responses
Lead Gen Forms
LinkedIn Lead Gen Forms share the same /v1/ads/lead-forms* endpoints as Meta, with the platform selected by accountId and the LinkedIn-shaped content inside platformSpecificData. LinkedIn forms are owned by the ad account's Company Page, so calls also take adAccountId.
Create a form
const { form } = await zernio.leadgen.createLeadForm({ body: {
accountId: 'ACCOUNT_ID',
name: 'Q3 Whitepaper form',
privacyPolicyUrl: 'https://example.com/privacy',
platformSpecificData: {
adAccountId: '517258773',
headline: 'Get the whitepaper',
description: "Fill in your details and we'll 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-10' }, { id: 2, text: '11-50' }] },
],
consents: [{ description: 'I agree to be contacted', required: true }],
},
}});form = client.lead_gen.create_lead_form(
account_id="ACCOUNT_ID",
name="Q3 Whitepaper form",
privacy_policy_url="https://example.com/privacy",
platform_specific_data={
"adAccountId": "517258773",
"headline": "Get the whitepaper",
"description": "Fill in your details and we'll 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-10"}, {"id": 2, "text": "11-50"}]},
],
"consents": [{"description": "I agree to be contacted", "required": True}],
},
)curl -X POST "https://zernio.com/api/v1/ads/lead-forms" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "ACCOUNT_ID",
"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-10" }, { "id": 2, "text": "11-50" } ] }
],
"consents": [ { "description": "I agree to be contacted", "required": true } ]
}
}'- Question kinds:
textandmultipleChoiceonly. LinkedIn's API does not expose profile-prefilled fields (EMAIL, FIRST_NAME, ...) — those exist in Campaign Manager's UI only. This is a LinkedIn API limitation, not ours. state:DRAFT(default) orPUBLISHED.consents[]: each{ description, required? }; Zernio maps them to LinkedIn's wire shape and assigns ids.
List / get / archive
GET /v1/ads/lead-forms?accountId=&adAccountId=— forms owned by the Company Page:{ id, name, state, headline, createdTime }.GET /v1/ads/lead-forms/{formId}?accountId=— the full form.DELETE /v1/ads/lead-forms/{formId}?accountId=— archives the form (state: ARCHIVED); LinkedIn has no hard delete.
Retrieve leads
GET /v1/ads/leads?accountId=&adAccountId=&formId=&since=&limit=&cursor=
const { leads } = await zernio.leadgen.listLeads({
query: { accountId: 'ACCOUNT_ID', adAccountId: '517258773', limit: 50 },
});
// rows: { id, formId, campaignId, adId, createdTime, fields } — fields maps question name -> answerleads = client.lead_gen.list_leads(
account_id="ACCOUNT_ID", ad_account_id="517258773", limit=50,
)curl "https://zernio.com/api/v1/ads/leads?accountId=ACCOUNT_ID&adAccountId=517258773&limit=50" \
-H "Authorization: Bearer YOUR_API_KEY"- 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.- The per-form
GET /v1/ads/lead-forms/{formId}/leadsandtest-leadsendpoints remain Meta-only: LinkedIn exposes no per-form finder, so filter withformIdon/v1/ads/leadsinstead.
Lead responses need the r_marketing_leadgen_automation scope. Connections made before it was added return a 403 telling you to reconnect; one pass through the LinkedIn connect flow fixes it. Form create/list/archive work without it.