Zernio
Zernio
PlatformsLinkedIn Ads

Build

Boost a PostCreate AdsCreative Formats

Target

Matched AudiencesBid Pricing & Forecasts

Measure

AnalyticsLead Gen FormsConversions APIURL Tracking Tags

Operate

Ad LibraryMedia & Limits
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
LinkedIn Ads

Create Ads

Create a single image or video ad on LinkedIn in one call, target it by industry, company size, seniority and job function, set bidding, reuse an existing campaign, and duplicate a campaign.


When you finish this page you can create a LinkedIn single image or video ad with POST /v1/ads/create, target it on LinkedIn's B2B facets, pick a bid, slot a creative into an existing campaign, and duplicate a campaign. You need a linkedinads account, a numeric ad account id and a Company Page.

Create a single image or video ad

Call POST /v1/ads/create with accountId, adAccountId, organizationId and the creative fields. No existing post is needed: Zernio creates a Direct Sponsored Content post authored by your Company Page (it never appears on the Page's feed), then wraps it in a Campaign Group, a Campaign and a Creative.

import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data: created } = await zernio.adcampaigns.createStandaloneAd({
  body: {
    accountId: '66b2e19d8c3f5a7e9d0b1c2d',
    adAccountId: '517258773',
    organizationId: '107655573',
    name: 'Spring launch (single image)',
    goal: 'traffic',
    budgetAmount: 50,
    budgetType: 'daily',
    headline: 'Schedule social posts in one API call',
    body: 'The social media API built for developers.',
    imageUrl: 'https://cdn.example.com/launch-1200x627.jpg',
    linkUrl: 'https://zernio.com',
    callToAction: 'LEARN_MORE',
    countries: ['US']
  }
});

console.log(created.ad._id);

Response (201):

{
  "ad": {
    "_id": "66f0a1b2c3d4e5f6a7b8c9d0",
    "name": "Spring launch (single image)",
    "platform": "linkedin",
    "status": "pending_review",
    "adType": "standalone",
    "goal": "traffic",
    "budget": { "amount": 50, "type": "daily" },
    "platformAdId": "376524873",
    "platformCampaignId": "645412093",
    "platformAdSetId": "810456563"
  },
  "message": "Ad created"
}

platformCampaignId is the LinkedIn Campaign Group and platformAdSetId the LinkedIn Campaign; _id is what the Insights and tracking tag endpoints take as adId.

organizationId names the Company Page that authors the post, as a numeric organization id or a full urn:li:organization:N URN. It is optional when the Page itself is connected as a Zernio account or the ad account is owned by an organization: Zernio infers it. The authenticated member must be an Administrator or Direct Sponsored Content Poster of that Page, and the Page must be associated with the ad account, or LinkedIn returns 403.

Field rules:

  • headline is required. Supply exactly one of imageUrl or video.
  • body becomes the post's intro text. longHeadline (optional) becomes the secondary description line on image link ads.
  • goal: "traffic" requires linkUrl.
  • callToAction accepts LEARN_MORE, SIGN_UP, DOWNLOAD, SUBSCRIBE, REGISTER, JOIN, ATTEND, REQUEST_DEMO, VIEW_QUOTE, APPLY, SEE_MORE, SHOP_NOW, BUY_NOW, and defaults to LEARN_MORE when linkUrl is set.
  • The recommended image ratio is 1.91:1 (1200 x 627), JPEG, PNG or GIF.
  • status: "PAUSED" leaves the Campaign Group, Campaign and Creative paused so you can review them before they spend. Omitted, Zernio activates the Campaign Group and Campaign, and the ad goes live the moment LinkedIn approves it.

The same imageUrl plus linkUrl shape also publishes LinkedIn's article and newsletter link ad; see Creative formats.

Video ads

Swap imageUrl for video: { url }; the two are mutually exclusive. Zernio uploads the clip to LinkedIn under the Company Page, the campaign format becomes SINGLE_VIDEO, and the video_views goal becomes available (it requires a video). LinkedIn generates the poster frame, so no thumbnail is needed. The request blocks while LinkedIn transcodes the video; short clips take 10 to 30 seconds. The file must be MP4 H.264/AAC, 3 seconds to 30 minutes, 75 KB to 500 MB.

{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "adAccountId": "517258773",
  "organizationId": "107655573",
  "name": "Spring launch (video)",
  "goal": "video_views",
  "budgetAmount": 50,
  "budgetType": "daily",
  "headline": "See it in action",
  "body": "The social media API built for developers.",
  "video": { "url": "https://cdn.example.com/launch.mp4" },
  "linkUrl": "https://zernio.com",
  "callToAction": "LEARN_MORE",
  "countries": ["US"]
}

Every other format (carousel, document, event, text ad, spotlight, follower, jobs, conversation, thought-leader) is a key inside platformSpecificData; see Creative formats.

Target the audience

countries: ['US'] above is the minimum LinkedIn accepts. The professional facets are what LinkedIn Ads are bought for, and they go in a nested targeting object, the same spec Bid pricing and forecasts prices and sizes before you spend:

{
  "targeting": {
    "countries": ["US", "GB"],
    "industries": ["4"],
    "companySizes": ["D", "E", "F"],
    "seniorities": ["4", "5"],
    "jobFunctions": ["8"]
  }
}
FieldValueMatched as
countriesISO 3166-1 alpha-2 codesLinkedIn geo URNs
regions[{ "key": ... }], each key a urn:li:geo:* URN from GET /v1/ads/targeting/search?dimension=geoThe same locations facet as countries
industriesIndustry id fragmentsurn:li:industry:{id}
companySizesStaff-count codes (below)urn:li:staffCountRange:{range}
senioritiesSeniority id fragmentsurn:li:seniority:{id}
jobFunctionsFunction id fragmentsurn:li:function:{id}
jobTitlesTitle id fragmentsurn:li:title:{id}
audienceInclude, audienceExcludeSegment ids from GET /v1/ads/audiencesurn:li:adSegment:{id}
excludedLocations.countriesISO 3166-1 alpha-2 codesThe exclude clause

A full URN passes through unchanged wherever an id fragment is accepted, so a value straight out of LinkedIn's own tooling works as it is.

companySizes takes a letter per staff-count range: A (1), B (2 to 10), C (11 to 50), D (51 to 200), E (201 to 500), F (501 to 1,000), G (1,001 to 5,000), H (5,001 to 10,000), I (10,001 and above).

3 rules decide whether the request survives:

  • LinkedIn requires at least one location. Send none and the ad targets the United States; send a country code outside the 45 Zernio maps and that code resolves to the United States too, so validate codes before spending on them.
  • jobTitles cannot be combined with seniorities or jobFunctions. LinkedIn rejects the whole ad, so Zernio returns a 400 with code mutually_exclusive_fields first.
  • cities, zips, metros, customLocations, incomeTier, behaviors and Meta's work facets return a 400 with code invalid_field_value naming the field: LinkedIn's Marketing API has no equivalent. ageMin, ageMax and gender are accepted on the request and ignored by LinkedIn.

Bidding

Bidding fields go in platformSpecificData, on both POST /v1/ads/create and POST /v1/ads/boost:

{
  "platformSpecificData": {
    "costType": "CPC",
    "unitCost": 2.5,
    "optimizationTargetType": "MAX_CLICK",
    "creativeSelection": "OPTIMIZED",
    "audienceExpansionEnabled": true,
    "offsiteDeliveryEnabled": false,
    "connectedTelevisionOnly": false
  }
}
FieldNotes
costTypeCPM (default), CPC, CPV. Required when unitCost is set.
unitCostManual bid in whole account-currency units. Omit for LinkedIn automated bidding.
optimizationTargetTypeForwarded verbatim (MAX_CLICK, TARGET_COST_PER_CLICK, ...).
creativeSelectionOPTIMIZED (default) or ROUND_ROBIN.
audienceExpansionEnabled, offsiteDeliveryEnabled, connectedTelevisionOnlyCampaign delivery toggles, forwarded verbatim.

Unknown keys inside platformSpecificData return a 400, and so do these LinkedIn-only keys on another platform's account. To pick a bid inside LinkedIn's allowed range before creating anything, call Bid pricing.

Reuse a campaign or campaign group you already have

By default each create mints a fresh Campaign Group, Campaign and Creative. Two optional, mutually exclusive fields slot into a hierarchy you already have; passing both returns a 400.

adSetId takes the numeric LinkedIn Campaign id and creates only a new Creative under it, skipping both provisioning steps. Bidding, targeting, schedule and budget are inherited from the Campaign, so sending those fields (including budgetType and budgetAmount) returns a 400:

{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "adAccountId": "517258773",
  "goal": "engagement",
  "platformSpecificData": { "thoughtLeader": { "postUrn": "urn:li:ugcPost:7482739454772752385" } },
  "adSetId": "810456563"
}

existingCampaignId takes a LinkedIn Campaign Group id and skips only the group provisioning: a new Campaign is created under that group, with bidding, targeting and schedule yours to set. If the create fails, only the entities Zernio authored are cleaned up; the pre-existing parent is never touched.

{
  "accountId": "66b2e19d8c3f5a7e9d0b1c2d",
  "adAccountId": "517258773",
  "goal": "engagement",
  "headline": "Schedule social posts in one API call",
  "body": "The social media API built for developers.",
  "imageUrl": "https://cdn.example.com/launch-1200x627.jpg",
  "linkUrl": "https://zernio.com",
  "budgetType": "daily",
  "budgetAmount": 20,
  "existingCampaignId": "1173166923"
}

Duplicate a campaign

Call POST /v1/ads/campaigns/{campaignId}/duplicate with platform: "linkedin" and the source Campaign Group id. LinkedIn has no native copy endpoint, so Zernio walks the source Campaign Group, its Campaigns and their Creatives and recreates the tree.

curl -X POST "https://zernio.com/api/v1/ads/campaigns/645412093/duplicate" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "platform": "linkedin",
    "statusOption": "PAUSED",
    "renameStrategy": "DEEP_RENAME",
    "renameSuffix": " (Copy)"
  }'

Response (200):

{
  "copiedCampaignId": "645498211",
  "discovery": "triggered"
}

discovery reports whether Zernio ran an ads sync straight after the copy so it shows up in GET /v1/ads/tree within seconds instead of at the next scheduled pass: triggered when it ran, skipped when the request sent syncAfter: false, and failed when the sync itself errored. The copy exists on LinkedIn in all 3 cases; failed and skipped only delay when Zernio sees it, so poll the tree.

The copy carries the campaign fields verbatim (type, costType, creativeSelection, unitCost, optimizationTargetType, targetingCriteria, dailyBudget, totalBudget, ...) and every Creative's content object, for DSC-authored, reference, document and thought-leader creatives alike. statusOption is PAUSED (default: the whole clone stays DRAFT), ACTIVE (the clone launches the moment LinkedIn approves it) or INHERITED_FROM_SOURCE (evaluated per entity: any Group, Campaign or Creative whose source is ACTIVE gets its clone activated too). If any step fails, only the entities the duplicate authored are cleaned up; the source tree is never touched.

INHERITED_FROM_SOURCE on an ACTIVE campaign starts a second front of spend the moment the clone activates. Keep PAUSED unless the caller wants a live clone.

Budget minimums

LinkedIn enforces a $10/day minimum for any ad format and a $100 minimum lifetime budget for inactive campaigns. Bid pricing returns the account-and-targeting-specific bounds; its dailyBudgetLimits.min is the authoritative number.

If it fails

A 403 on create means the member lacks the Direct Sponsored Content Poster or Administrator role on the Page, or the Page is not associated with the ad account. LinkedIn's REST error is forwarded verbatim inside Zernio's platform_error envelope:

{
  "error": "LinkedIn rejected the request",
  "type": "platform_error",
  "code": "platform_api_error",
  "platform": "linkedin",
  "platformError": { "status": 403, "message": "Not enough permissions to access: ..." }
}

Fix the Page role in LinkedIn, then repeat the call. Error handling covers the envelope.

Related

  • Creative formats: every other creative shape.
  • Boost a post: promote an existing Company Page post instead.
  • Bid pricing and forecasts: pick a bid and budget before creating.
  • Create standalone ad: every field of the request.
  • Duplicate a campaign: the full body.
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

Create a single image or video adVideo adsTarget the audienceBiddingReuse a campaign or campaign group you already haveDuplicate a campaignBudget minimumsIf it failsRelated