Create Ads
Single image and video ads, bidding, reusing existing hierarchy, and duplication
Create a Single Image or Video Ad
Build an ad from scratch, no existing post needed. Zernio creates a Direct Sponsored Content ("dark post") authored by your Company Page (it never appears on the Page's feed; it only runs as the ad), then wraps it in a campaign group, campaign, and creative.
const ad = await zernio.adcampaigns.createStandaloneAd({ body: {
accountId: "ACCOUNT_ID",
adAccountId: "517258773", // numeric sponsored account ID
organizationId: "107655573", // Company Page that authors the ad (or "urn:li:organization: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.", // post commentary (intro text above the ad)
imageUrl: "https://cdn.example.com/launch-1200x627.jpg",
linkUrl: "https://zernio.com", // destination, required when goal is "traffic"
callToAction: "LEARN_MORE", // defaults to LEARN_MORE when linkUrl is set
countries: ["US"],
}});ad = client.ad_campaigns.create_standalone_ad(
account_id="ACCOUNT_ID",
ad_account_id="517258773",
organization_id="107655573",
name="Spring launch (single image)",
goal="traffic",
budget_amount=50,
budget_type="daily",
headline="Schedule social posts in one API call",
body="The social media API built for developers.",
image_url="https://cdn.example.com/launch-1200x627.jpg",
link_url="https://zernio.com",
call_to_action="LEARN_MORE",
countries=["US"],
)curl -X POST "https://zernio.com/api/v1/ads/create" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "ACCOUNT_ID",
"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"]
}'The ad runs as a Direct Sponsored Content post authored by a Company Page. Pass that page via organizationId (a numeric organization ID or a full urn:li:organization:N URN). If you connected the page itself as a Zernio account, or your ad account is owned by an organization, it's inferred and organizationId is optional. The authenticated LinkedIn 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. Recommended image ratio 1.91:1 (e.g. 1200×627), JPEG/PNG/GIF.
The same imageUrl + linkUrl shape also publishes LinkedIn's article / newsletter link ad, no special format needed, see Creative Formats.
Video ads
For a single video ad, swap imageUrl for video: { url } (the two are mutually exclusive). The clip is uploaded to LinkedIn under the Company Page, the campaign format becomes SINGLE_VIDEO, and the video_views goal becomes available (it requires a video). LinkedIn auto-generates the poster frame, so a thumbnail isn't required. The request blocks while LinkedIn transcodes the video (short clips take ~10-30s).
const ad = await zernio.adcampaigns.createStandaloneAd({ body: {
accountId: "ACCOUNT_ID",
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" }, // MP4 H.264/AAC, 3s-30min, 75KB-500MB
linkUrl: "https://zernio.com", // optional unless goal is "traffic"
callToAction: "LEARN_MORE",
countries: ["US"],
}});For every other format (carousel, document, event, text ad, spotlight, follower, jobs, conversation, thought-leader), see Creative Formats.
Bidding
Bidding fields ride on 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
}
}| Field | Notes |
|---|---|
costType | CPM (default), CPC, CPV. Required when unitCost is set. |
unitCost | Manual bid in whole account-currency units. Omit for LinkedIn automated bidding. |
optimizationTargetType | Forwarded verbatim (e.g. MAX_CLICK, TARGET_COST_PER_CLICK). |
creativeSelection | OPTIMIZED (default) or ROUND_ROBIN. |
audienceExpansionEnabled / offsiteDeliveryEnabled / connectedTelevisionOnly | Campaign delivery toggles, forwarded verbatim. |
Unknown keys inside platformSpecificData return a 400, and so does platformSpecificData on a non-LinkedIn account. To pick a bid inside LinkedIn's allowed range before creating anything, use Bid Pricing.
Reuse an existing Campaign or Campaign Group
By default each create mints a fresh Campaign Group + Campaign + Creative. Two optional, mutually exclusive fields let you slot into existing hierarchy:
existingCampaignId — create only a new Creative under that Campaign. Zernio reads the parent to derive the Campaign Group and currency and skips both provisioning steps. Bidding, targeting, schedule, budget and currency are inherited from the Campaign, passing them is ignored, and budgetType / budgetAmount become optional.
{
"accountId": "...", "adAccountId": "517258773",
"goal": "engagement",
"platformSpecificData": { "thoughtLeader": { "postUrn": "urn:li:ugcPost:..." } },
"existingCampaignId": "810456563"
}existingCampaignGroupId — skip only Group provisioning; a new Campaign is created under the given group, with bidding / targeting / schedule yours to set.
{
"accountId": "...", "adAccountId": "517258773",
"goal": "engagement",
"headline": "...", "body": "...",
"imageUrl": "...", "linkUrl": "...",
"budgetType": "daily", "budgetAmount": 20,
"existingCampaignGroupId": "1173166923"
}Passing both returns a 400.
Duplicate a campaign
POST /v1/ads/campaigns/{campaignId}/duplicate with platform: "linkedin" walks the source Campaign Group → Campaigns → Creatives and recreates the pyramid (LinkedIn has no native copy endpoint, so Zernio rebuilds it).
{
"platform": "linkedin",
"statusOption": "PAUSED",
"renameStrategy": "DEEP_RENAME",
"renameSuffix": " (Copy)"
}- Copied verbatim: 15 campaign fields (
type,costType,creativeSelection,unitCost,optimizationTargetType,targetingCriteria,dailyBudget,totalBudget, ...) and every Creative's content object (works for DSC-authored, reference, document, and thought-leader creatives). statusOption:PAUSED(default, the whole clone stays DRAFT, safe) ·ACTIVE(the clone launches the moment LinkedIn approves it) ·INHERITED_FROM_SOURCE(evaluated per entity: any Group / Campaign / Creative whose source is ACTIVE gets its clone activated too).- Rollback: if any step fails, only the entities the duplicate authored are cleaned up; the source graph is never touched.
INHERITED_FROM_SOURCE on an ACTIVE campaign starts a second front of spend the moment the clone activates. Default to PAUSED unless the caller explicitly wants a live clone.
Budget minimums
LinkedIn enforces a $10/day minimum for any ad format and $100 minimum lifetime budget for inactive campaigns. Check Bid Pricing for the account-and-targeting-specific bounds before creating, its dailyBudgetLimits.min is the authoritative number.