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

Conversions API

Send offline conversion events to LinkedIn with POST /v1/ads/conversions, manage conversion rules, and read attribution back.


By the end of this page, an offline conversion (deal closed, lead qualified, trial converted, purchase) reaches LinkedIn through POST /v1/ads/conversions, the same endpoint as Meta and Google.

Before you start

You need a connected linkedinads account and a conversion rule id. Find or create a conversion rule gets you one.

Accounts connected before Zernio shipped Conversions API support must reconnect. LinkedIn does not upgrade an existing OAuth grant with the rw_conversions scope; accounts that lack it return 403 with code linkedin_reconnect_required. One pass through the LinkedIn connect flow fixes it.

Send a conversion event

Call POST /v1/ads/conversions with accountId, the conversion rule id as destinationId and the events.

Zernio uses the LinkedIn account you already connected. There is no separate Conversions API token to generate in Campaign Manager.

Send PII as plaintext. Zernio SHA-256 hashes it per LinkedIn's spec before anything reaches LinkedIn.

externalId is passed through as plaintext, per LinkedIn's requirement.

TypeScript
import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data: sent } = await zernio.conversions.sendConversions({
  body: {
    accountId: '66b2e19d8c3f5a7e9d0b1c2d',
    destinationId: '25639412',
    events: [{
      eventName: 'Lead',
      eventTime: 1798848000,
      eventId: 'order_abc_123',
      value: 42.5,
      currency: 'USD',
      user: {
        email: 'customer@example.com',
        firstName: 'Jane',
        lastName: 'Doe',
        country: 'US',
        clickIds: { li_fat_id: 'AQH...' }
      }
    }]
  }
});

console.log(sent.eventsReceived, sent.eventsFailed);

Response (200):

JSON
{
  "platform": "linkedinads",
  "eventsReceived": 1,
  "eventsFailed": 0,
  "failures": []
}

eventName is informational on LinkedIn. The rule's type, set at creation, decides the conversion category.

clickIds.li_fat_id is optional and improves the match rate. Capture it from li_fat_id on landing-page URLs after enabling enhanced conversion tracking on the LinkedIn Insight Tag.

User identifiers

LinkedIn requires at least one of:

  • a SHA-256-hashed email
  • a LinkedIn first-party click id (li_fat_id)
  • an Acxiom or Oracle MOAT identifier
  • both firstName and lastName

Send as many as you have. Hashed identifiers improve the match rate.

Deduplication

Pass a stable eventId on every event.

If you also fire the LinkedIn Insight Tag with the same event id, LinkedIn discards the Conversions API copy. It counts only the Insight Tag event (Idempotency covers the same rule on posts).

Find or create a conversion rule

Call GET /v1/accounts/{accountId}/conversion-destinations.

It returns every CONVERSIONS_API rule across every sponsored ad account the connected token can access. Each carries the adAccountId you pass back on later calls.

TypeScript
const { data: destinations } = await zernio.conversions.listConversionDestinations({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' }
});

console.log(destinations.destinations);

Response (200):

JSON
{
  "platform": "linkedinads",
  "destinations": [
    { "id": "25639412", "name": "Trial activation", "type": "LEAD", "status": "active", "adAccountId": "517258773" }
  ]
}

To create a rule, call POST /v1/accounts/{accountId}/conversion-destinations. A LinkedIn rule binds an event type (LEAD, PURCHASE, ADD_TO_CART, ...) to the destination.

By default the new rule is auto-associated with every campaign in the ad account. autoAssociationType changes that:

  • "OBJECTIVE_BASED": associate only the campaigns whose objective matches the rule type
  • "NONE": opt out and manage associations explicitly (Step 3)
TypeScript
const { data: rule } = await zernio.conversions.createConversionDestination({
  path: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' },
  body: {
    adAccountId: '517258773',
    name: 'Trial activation',
    type: 'Lead',
    attributionType: 'LAST_TOUCH_BY_CAMPAIGN'
  }
});

console.log(rule.destination.id);

Response (201):

JSON
{
  "platform": "linkedinads",
  "destination": { "id": "25639412", "name": "Trial activation", "type": "LEAD", "status": "active", "adAccountId": "517258773" }
}

The attribution windows keep LinkedIn's defaults unless you set them:

  • postClickAttributionWindowSize, default 30 days
  • viewThroughAttributionWindowSize, default 7 days

Each takes 1, 7, 30, 90 or 365. 365 is allowed only for the LEAD, PURCHASE, ADD_TO_CART, QUALIFIED_LEAD and SUBMIT_APPLICATION rule types.

adAccountId is numeric or urn:li:sponsoredAccount:....

type is a unified name, or a LinkedIn enum ("QUALIFIED_LEAD", "OUTBOUND_CLICK") for types outside the unified set:

UnifiedLinkedIn
PurchasePURCHASE
LeadLEAD
CompleteRegistrationCOMPLETE_SIGNUP
AddToCartADD_TO_CART
InitiateCheckoutSTART_CHECKOUT
AddPaymentInfoADD_BILLING_INFO
SubscribeSUBSCRIBE
StartTrialSTART_TRIAL
ViewContentVIEW_CONTENT
SearchSEARCH
ContactCONTACT
SubmitApplicationSUBMIT_APPLICATION
ScheduleSCHEDULE

Creation is not idempotent on LinkedIn. A retry creates a second rule.

Associate campaigns

By default createConversionDestination auto-associates the new rule with every active, paused and draft campaign in the ad account (autoAssociationType: "ALL_CAMPAIGNS").

Auto-association runs once at create time. Campaigns added later need an explicit association with POST /v1/accounts/{accountId}/conversion-destinations/{destinationId}/associations:

Terminal
curl -X POST "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/conversion-destinations/25639412/associations" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "adAccountId": "517258773", "campaignIds": ["337643194", "345396555"] }'

Response (200), a per-campaign result so you can retry only the rows that failed:

JSON
{
  "platform": "linkedinads",
  "succeeded": ["337643194"],
  "failed": [{ "campaignId": "345396555", "reason": "Campaign objective does not match the rule type" }]
}

Attribution metrics

Read conversion attribution back from LinkedIn's adAnalytics endpoint, pivoted by date, with GET /v1/accounts/{accountId}/conversion-destinations/{destinationId}/metrics:

Terminal
curl "https://zernio.com/api/v1/accounts/66b2e19d8c3f5a7e9d0b1c2d/conversion-destinations/25639412/metrics?adAccountId=517258773&startDate=2027-01-01&endDate=2027-01-31&granularity=DAILY" \
  -H "Authorization: Bearer $ZERNIO_API_KEY"

Response (200):

JSON
{
  "platform": "linkedinads",
  "granularity": "DAILY",
  "rows": [
    {
      "start": "2027-01-01",
      "end": "2027-01-01",
      "metrics": {
        "externalWebsiteConversions": 4,
        "externalWebsitePostClickConversions": 3,
        "externalWebsitePostViewConversions": 1,
        "conversionValueInLocalCurrency": 170,
        "qualifiedLeads": 0,
        "costInLocalCurrency": 38.2
      }
    }
  ]
}

LinkedIn's retention rules apply:

  • granularity=DAILY covers roughly the last 6 months.
  • MONTHLY and YEARLY extend to 24 months.
  • granularity=ALL with a range over 6 months rounds to month boundaries.

Soft delete

LinkedIn does not expose a hard delete on conversion rules. This call flips enabled: false, the same operation Campaign Manager's delete performs:

Text
DELETE /v1/accounts/{accountId}/conversion-destinations/{destinationId}?adAccountId=517258773

The rule remains fetchable as status: "inactive".

Limits

  • LinkedIn's BATCH_CREATE cap is 5,000 events, and Zernio chunks a larger events array into 5,000-event calls for you. Each chunk is all-or-nothing on LinkedIn's side.
  • 600 requests per minute and 300,000 per day per token (LinkedIn-side).
  • eventTime must be within the last 90 days. Zernio does not enforce the bound, so an older event reaches LinkedIn and is rejected there.

If it fails

ErrorCauseFix
403 linkedin_reconnect_requiredThe connection lacks the rw_conversions scopeSend the user through the LinkedIn connect flow again (scopes) and repeat the call
200 with eventsFailed above 0LinkedIn rejected events, and each 5,000-event chunk is all-or-nothingFix the events failures[] names and resend them
LinkedIn rejects an event Zernio acceptedeventTime is older than 90 days, which Zernio does not checkSend events from the last 90 days
A second rule after a retryRule creation is not idempotent on LinkedInList rules before creating one again
A campaign in failed on associationsLinkedIn refused that campaign, for example an objective that does not match the rule typeRetry only the failed rows, or use a matching rule

The 403 body:

JSON
{
  "error": "The LinkedIn connection lacks the rw_conversions scope. Reconnect the account.",
  "type": "permission_error",
  "code": "linkedin_reconnect_required"
}

Related

  • Analytics: firmographic breakdowns of the same campaigns.
  • Meta Ads Conversions API and Google Ads conversions: the same endpoint on the other networks.
  • Send conversions and Create a conversion destination: every field.
Was this page helpful?

Analytics

Read spend, clicks and firmographic breakdowns (job title, seniority, industry, company size) for a LinkedIn ad with the Insights endpoints.

Insight Tag

Read, create and share a LinkedIn Insight Tag, manage its conversion rules, check when it last fired, and install it on Shopify or WordPress.

On this page

Before you startSend a conversion eventUser identifiersDeduplicationFind or create a conversion ruleAssociate campaignsAttribution metricsSoft deleteLimitsIf it failsRelated