Zernio
APIFor you
Zernio
APIFor you
Platforms

LinkedIn Ads

Overview

Build

Create adsBoost a postLead Gen FormsCreative formats

Target

TargetingMatched AudiencesBid pricing & forecasts

Measure

AnalyticsConversions APIInsight TagURL tracking tags

Operate

Manage adsAd Library

Reference

Media & limits
Dashboard
OverviewPlatformsAPI ReferenceResources
LinkedIn Ads

Lead Gen Forms

Create LinkedIn Lead Gen Forms with POST /v1/ads/lead-forms and pull their responses with GET /v1/ads/leads.


By the end of this page, you have a LinkedIn Lead Gen Form and a way to pull its responses.

Before you start

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. That object carries adAccountId, headline, description and at least one question.

Every question needs kind, name and question. A multipleChoice question also needs choices.

TypeScript
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):

JSON
{
  "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 text and multipleChoice only. LinkedIn's API does not expose profile-prefilled fields (EMAIL, FIRST_NAME, ...); those exist in Campaign Manager's UI only.
  • state is DRAFT (default) or PUBLISHED.
  • consents[] entries are { description, required? }; Zernio maps them to LinkedIn's wire shape and assigns ids.
  • maxResponseLength defaults 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. Add 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.

TypeScript
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):

JSON
{
  "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.
  • since is Unix seconds; cursor is the numeric offset from pagination.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. Zernio turns LinkedIn's 403 into an actionable reconnect prompt.

Form create, list and archive work without the scope. Reading responses does not.

JSON
{
  "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" and leadGenFormId.
  • Meta Ads lead forms: the Meta shape of the same endpoints.
  • Create a lead form and List submitted leads: every field.
Was this page helpful?

Boost a post

Promote an existing LinkedIn Company Page post as an ad with POST /v1/ads/boost, keeping its reactions and comments, on any of the 6 goals boost accepts.

Creative formats

Select carousel, document, event, text, spotlight, follower, jobs, conversation and thought-leader ads with one key inside platformSpecificData.

On this page

Before you startCreate a formList, get and archiveRetrieve leadsIf it failsRelated