Manage ads
Pause and resume LinkedIn campaign groups, campaigns and creatives, change a campaign's budget, swap a creative's media, rename, duplicate and delete.
By the end of this page, you can stop and restart a LinkedIn ad, change what it spends and looks like, copy it and remove it.
Before you start
You need a linkedinads account and an ad. Zernio's levels map onto LinkedIn's like this:
| Zernio | Id on the created ad | |
|---|---|---|
| Campaign | Campaign Group | platformCampaignId |
| Ad set | Campaign | platformAdSetId |
| Ad | Creative | platformAdId |
Pause or resume
PUT /v1/ads/campaigns/{campaignId}/status writes the Campaign Group's own switch and nothing else. Its Campaigns and Creatives keep their own switches.
import Zernio from '@zernio/node';
const zernio = new Zernio();
const { data: paused } = await zernio.adcampaigns.updateAdCampaignStatus({
path: { campaignId: '645412093' },
body: { status: 'paused', platform: 'linkedin' }
});Response (200):
{ "status": "paused", "platformCampaignStatus": null, "statusReadAt": null, "updated": 1, "skipped": 0 }LinkedIn has no single Campaign Group read, so platformCampaignStatus and statusReadAt are always null and the write always goes out.
Resuming a group lets each Campaign and Creative deliver again only if its own switch is on. Narrower scopes take the same status:
| Scope | Call | LinkedIn switch |
|---|---|---|
| One Campaign | PUT /v1/ads/ad-sets/{adSetId}/status | The Campaign |
| One Creative | PUT /v1/ads/{adId}/status | The Creative, so sibling Creatives keep running |
A Creative still in DRAFT is already held off, and LinkedIn refuses to pause it before its review is approved. Pausing one writes nothing.
Change the budget
Send budget on PUT /v1/ads/{adId}. Zernio writes it to the ad's LinkedIn Campaign, so it covers every Creative in that Campaign.
{ "budget": { "amount": 40, "type": "daily" } }LinkedIn's minimums still apply (Budget minimums).
Swap the creative
Send creative on PUT /v1/ads/{adId} with new media in imageUrl or videoUrl, plus headline, body, description, callToAction and linkUrl as needed.
Zernio uploads the media, creates a new Creative on the same Campaign and pauses the old one. The old Creative is kept for reporting.
A text-only update returns 400, because LinkedIn needs new media. videoId and existingCreativeId are Meta-only and return 400.
Rename
name on PUT /v1/ads/ad-sets/{adSetId} renames the LinkedIn Campaign.
LinkedIn Creatives cannot be renamed: name on PUT /v1/ads/{adId} returns 501.
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. Zernio walks the source Campaign Group, its Campaigns and their Creatives and recreates the tree.
const { data: copy } = await zernio.adcampaigns.duplicateAdCampaign({
path: { campaignId: '645412093' },
body: {
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. The sync makes the copy show up in GET /v1/ads/tree within seconds instead of at the next scheduled pass.
triggered: the sync ranskipped: the request sentsyncAfter: falsefailed: 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, ...).
It also carries every Creative's content object, for DSC-authored, reference, document and thought-leader creatives alike.
statusOption takes one of:
PAUSED(default): the whole clone staysDRAFTACTIVE: the clone launches the moment LinkedIn approves itINHERITED_FROM_SOURCE: evaluated per entity. Any Group, Campaign or Creative whose source isACTIVEgets 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.
Delete
| Level | Call | What LinkedIn does |
|---|---|---|
| Ad | DELETE /v1/ads/{adId} | Removes the Creative. Its Campaign and Campaign Group go too, but only when Zernio created them and nothing else live is left in them. |
| Ad set | DELETE /v1/ads/ad-sets/{adSetId} | Moves the Campaign to PENDING_DELETION. It stays readable for reporting, and its ads are marked cancelled. |
| Campaign | DELETE /v1/ads/campaigns/{campaignId} | Moves the Campaign Group to PENDING_DELETION. Its ads are marked cancelled. |
If the Creative itself cannot be removed, the request fails and no parent is touched.
A Campaign Group with no ads in Zernio is deleted only after LinkedIn confirms it holds no Campaigns. To delete one, send accountId in the body or the query string.
If it fails
| Error | Cause | Fix |
|---|---|---|
400 on creative | The update carries no imageUrl or videoUrl, or a Meta-only field | Send new media |
501 on name on an ad | LinkedIn Creatives cannot be renamed | Rename the Campaign with PUT /v1/ads/ad-sets/{adSetId} |
501 on bidStrategy on an ad set | Zernio does not change LinkedIn bidding after create | Set bidding in platformSpecificData at create (Bidding) |
409 invalid_resource_state on a campaign delete | The empty group was never synced, or LinkedIn still lists Campaigns in it | Sync the ad account (POST /v1/ads/sync) and delete again |
discovery: "failed" on a duplicate | The sync after the copy errored | The copy exists on LinkedIn, so poll GET /v1/ads/tree |
Related
- Create a campaign: the hierarchy these calls manage.
- Targeting: change a running Campaign's audience.
- Pause or resume a campaign and Update ad: every field.
- Duplicate a campaign and Delete a campaign: the full bodies.