Zernio
APIFor you
Zernio
APIFor you
API Reference

Campaigns and Ads

Overview

Get campaign treeGETGet daily account metricsGET

Campaigns

List campaignsGETCreate a standalone campaignPOSTGet live campaign detailsGETUpdate a campaignPUTDuplicate a campaignPOSTDelete a campaignDELETEPause or resume a campaignPUTPause or resume many campaignsPOSTList campaign assetsGETAttach campaign assetsPOSTUpdate campaign assetsPUTRemove campaign assetsDELETERead a Google campaign's device, location, excluded location, and language targetingGETEdit a Google campaign's device, location, excluded location, or language targetingPUTRead a campaign's ad schedule (dayparting)GETReplace a campaign's ad schedule (dayparting)PUTGet campaign conversion goalsGETUpdate campaign conversion goalsPATCH

Asset Groups

List Performance Max asset groupsGETCreate a Performance Max asset groupPOSTGet a Performance Max asset groupGETUpdate a Performance Max asset groupPATCHRemove a Performance Max asset groupDELETELink or unlink asset group assetsPOSTReplace an asset group's listing-group treePUT

Ad Sets

List ad setsGETCreate a standalone ad groupPOSTGet live ad-set detailsGETUpdate an ad setPUTDuplicate an ad setPOSTDelete an ad setDELETEPause or resume a single ad setPUTList ad-group assetsGETAttach ad-group assetsPOSTUpdate ad-group assetsPUTRemove ad-group assetsDELETE

Ads

List adsGETGet ad detailsGETCreate standalone adPOSTBoost post as adPOSTUpdate adPUTDuplicate an adPOSTCancel an adDELETEPause or resume a single adPUT

Keywords

List Search keywordsGETAdd Search ad-group keywordsPOSTPause or enable a Search keywordPATCHRemove a Search keywordDELETEList campaign-level negative keywordsGETReplace campaign-level negative keywordsPUTList campaign negative listsGETReplace campaign negative listsPUT

Bidding

Read a campaign's current biddingGETList portfolio bid strategiesGETCreate portfolio bid strategyPOSTUpdate portfolio bid strategyPATCH

Recommendations

List Google Ads recommendationsGETApply Google Ads recommendationsPOSTDismiss Google Ads recommendationsPOST

Other

Create a shared budgetPOSTRead the platform's review verdict for an adGETReview status of each creative in a TikTok Smart+ adGETList shared budgetsGETReview status of every TikTok Smart+ ad of an advertiserGET
Dashboard
OverviewPlatformsAPI ReferenceResources
Campaigns and Ads

Update a campaign

Changes a campaign's settings, such as its name, budget, bidding or tracking URLs.

Send at least one of budget, bidStrategy, portfolioBidStrategyId, targetImpressionShare, manualCpc, networkSettings, trackingUrlTemplate, finalUrlSuffix, sharedBudgetId, name or platformSpecificData. An unsupported field is always an error, never a silent drop.

Body fieldMetaGoogleOthers
bidStrategyYesYes501
bidAmount, roasAverageFloor400 (ad-set level)Yes400
portfolioBidStrategyId400Yes400
targetImpressionShare400Search only400
manualCpc400Search and Display400
networkSettings400Search only400
trackingUrlTemplate, finalUrlSuffix400Yes400
sharedBudgetId400Yes400
budget (CBO; ABO returns 409)YesDaily onlyOpenAI and Reddit: daily or lifetime; others 501
nameYes501Reddit: Yes; others 501
platformSpecificData.spendCapYes400400
accountId (empty campaigns)Yes--

Meta budget edits check the live campaign budget, so an older local ABO stamp cannot block a CBO campaign. A successful edit repairs local ad budget fields. A live ABO campaign still returns 409 with the ad-set budget endpoint.

On Google: LOWEST_COST_WITHOUT_CAP = Maximize Conversions, COST_CAP + bidAmount = Target CPA, LOWEST_COST_WITH_MIN_ROAS + roasAverageFloor = Target ROAS, LOWEST_COST_WITH_BID_CAP + bidAmount = Maximize Clicks with a CPC ceiling; portfolioBidStrategyId attaches a portfolio strategy instead (exclusive with bidStrategy). targetImpressionShare switches the campaign to Target impression share and manualCpc: { maxCpc } to Manual CPC (every ad group of the campaign gets maxCpc as its bid, in the same mutate); each is exclusive with every other strategy field. networkSettings, trackingUrlTemplate and finalUrlSuffix go out in one campaign update, each field sent written on its own leaf, so an omitted one keeps its current value; an empty string clears a URL field. Setting the standard triplet on a campaign that is currently on a PORTFOLIO strategy is rejected: detach it in Google Ads first, since it is shared across campaigns.

Google budget updates read the current budget before mutation. Shared budgets return 409 unless allowSharedBudgetUpdate=true is explicitly supplied, because the change affects every campaign using that budget. A budget counts as shared when Google flags it as shared or when more than one campaign uses it (older budgets can serve several campaigns without the flag). Unknown sharing state also returns 409.

sharedBudgetId (Google) moves the campaign onto a shared budget from GET /v1/ads/shared-budgets, which also needs allowSharedBudgetUpdate: true (409 otherwise) because the campaign then splits that budget with every campaign on it; budget cannot ride along. sharedBudgetId: null moves it back onto a new budget of its own, sized by budget (required, daily); the new budget and the switch go out in one atomic Google mutate. A campaign that already has its own budget returns 409 for null. The budget a campaign leaves is not removed. The response carries the budget the campaign now uses.

OpenAI Ads campaigns carry exactly one spend cap: budget.type daily or lifetime replaces whichever cap the campaign had, with a minimum of 1 in the ad account's currency (422 below it). Lifetime can switch to daily, but OpenAI never switches a daily cap back to lifetime (422).

Reddit Ads: budget changes the amount of a campaign budget (Reddit campaign budget optimization); a campaign whose ad groups carry the budget returns 409 or 422, use PUT /v1/ads/ad-sets/{adSetId} there. Reddit cannot switch a published budget between daily and lifetime, so budget.type must match the current one (422 otherwise). bidStrategy is set per ad group on Reddit (PUT /v1/ads/ad-sets/{adSetId}).

accountId forwards the update straight to Meta for a campaign with zero ads, which would otherwise 404; the response then carries updated: 0.


PlatformsMetaGoogleTikTokLinkedInPinterestXOpenAI
PUT
/v1/ads/campaigns/{campaignId}

Authorization

bearerAuth
AuthorizationBearer <token>

API key authentication: send your Zernio API key in the Authorization header, prefixed with Bearer.

In: header

Path Parameters

campaignId*string

Platform campaign ID

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

import Zernio from '@zernio/node';const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });const { data } = await zernio.adcampaigns.updateAdCampaign({  path: {    campaignId: 'campaign_abc123',  },  body: {    platform: 'facebook',  },});console.log(data);
{  "updated": 0,  "budget": {    "amount": 0,    "type": "daily",    "amountMicros": "string",    "explicitlyShared": true,    "resourceName": "string",    "deliveryMethod": "string"  },  "budgetLevel": "campaign",  "bidStrategy": "LOWEST_COST_WITHOUT_CAP",  "bidAmount": 0,  "roasAverageFloor": 0,  "portfolioBidStrategyId": "string",  "targetImpressionShare": {    "location": "ANYWHERE_ON_PAGE",    "percent": 1,    "maxCpc": 1  },  "manualCpc": {    "maxCpc": 1  },  "networkSettings": {    "searchPartners": true,    "displayNetwork": true  },  "trackingUrlTemplate": "string",  "finalUrlSuffix": "string",  "sharedBudgetId": "string",  "platformSpecificData": {}}
Was this page helpful?

Get live campaign details

Shows a Meta campaign's current settings straight from Meta, such as its objective, budget, bid strategy, schedule and delivery issues. Reads one campaign live from Meta, returned verbatim, so a caller that knows a campaign id no longer has to page `GET /v1/ads/campaigns` to find it. The default projection covers name, status, objective, buying type, bid strategy, budgets, spend cap, schedule and `issues_info`. `fields` is a raw-passthrough override; unknown fields return Meta's 400 verbatim. A campaign the resolved connection cannot see comes back as Meta's own 400, not a 404.

Duplicate a campaign

Copies a campaign with its ad sets, ads, creatives and targeting, created paused so you can review it before launch. Duplicates a campaign, including its ad sets, ads, creatives, and targeting by default (`deepCopy: true`). The copy is created paused so callers can review before launching. Per-platform implementation: - **Meta** uses the native `POST /{campaign-id}/copies` endpoint. - **TikTok** has no native copy primitive; Zernio walks the source graph (`/v2/campaign/get/`, `/v2/adgroup/get/`, `/v2/ad/get/`) and recreates each entity via the corresponding `/create/` endpoints, carrying over budget / targeting / bid_type / bid_price / deep_bid_type / creative fields. Spark Ad linkage (`tiktok_item_id`) is preserved. - **LinkedIn** has no native copy primitive; Zernio walks the source CampaignGroup → Campaigns → Creatives and recreates each entity, carrying over `type` / `costType` / `unitCost` / `optimizationTargetType` / `creativeSelection` / `objectiveType` / `format` / `dailyBudget` / `totalBudget` / `targetingCriteria` / `runSchedule` and every Creative's `content` object verbatim. `statusOption: INHERITED_FROM_SOURCE` is evaluated **per entity**: any Group / Campaign / Creative whose source is `ACTIVE` gets its clone activated too. Duplicating an ACTIVE campaign with `INHERITED_FROM_SOURCE` starts a second front of spend the moment the clone activates. The safe default is `PAUSED`. The new hierarchy is asynchronous to materialize in our DB, and we trigger sync discovery automatically. Set `syncAfter: false` to skip and poll `/v1/ads/tree` on your own cadence. Other platforms return 501 Not Implemented.

platform*string

Required: platform campaign IDs are not globally unique.

Value in

  • "facebook"
  • "instagram"
  • "tiktok"
  • "linkedin"
  • "pinterest"
  • "google"
  • "twitter"
  • "openai"
  • "reddit"
accountId?string

Meta only. Zernio SocialAccount id owning the ad account. Needed only for an EMPTY campaign (zero ads); ignored otherwise.

bidStrategy?string

Meta + Google. On Meta, the campaign default that ad sets inherit unless they override it. On Google, the campaign's own bidding strategy. On Google: LOWEST_COST_WITHOUT_CAP = Maximize Conversions, COST_CAP + bidAmount = Target CPA, LOWEST_COST_WITH_MIN_ROAS + roasAverageFloor = Target ROAS, LOWEST_COST_WITH_BID_CAP + bidAmount = Maximize Clicks with a CPC ceiling; portfolioBidStrategyId attaches a portfolio strategy instead.

Value in

  • "LOWEST_COST_WITHOUT_CAP"
  • "LOWEST_COST_WITH_BID_CAP"
  • "COST_CAP"
  • "LOWEST_COST_WITH_MIN_ROAS"
bidAmount?number

Google only. Whole currency units (USD: 12 = $12.00). Max CPC for LOWEST_COST_WITH_BID_CAP, CPA target for COST_CAP; required for both.

roasAverageFloor?number

Google only. Decimal ROAS multiplier (2.0 = 2.0x), required for LOWEST_COST_WITH_MIN_ROAS.

portfolioBidStrategyId?string

Google only. Attach an existing portfolio bid strategy (numeric id from GET /v1/ads/bid-strategies) instead of setting bidStrategy. Exclusive with bidStrategy.

Match^\d+$
allowSharedBudgetUpdate?boolean

Google only. Explicitly allow changing a shared campaign budget (flagged as shared by Google, or used by more than one campaign), affecting every campaign that uses it. Does not bypass an unknown sharing state. Also required to move a campaign onto a shared budget with sharedBudgetId.

Defaultfalse
targetImpressionShare?

Google Search only. Target impression share bidding. Exclusive with bidStrategy, portfolioBidStrategyId and manualCpc; bidAmount is refused alongside it (the ceiling is maxCpc).

manualCpc?

Google Search and Display only. Manual CPC bidding. Enhanced CPC is not offered: Google no longer lets Search and Display campaigns enable it. Exclusive with every other strategy field.

networkSettings?

Google Search campaigns only. Which networks the campaign serves on besides Google Search. When omitted at creation, search partners are ON and the Display Network is OFF (the defaults Zernio has always used); on an update only the fields sent change.

Properties1 <= properties
trackingUrlTemplate?string

Google only. campaign.tracking_url_template; an empty string clears it.

finalUrlSuffix?string

Google only. campaign.final_url_suffix; an empty string clears it.

sharedBudgetId?|

Google only. Move the campaign onto this shared budget (id from GET /v1/ads/shared-budgets), or null to move it back onto a budget of its own sized by budget.

Match^\d+$
budget?

Meta CBO, Google daily, or OpenAI Ads or Reddit Ads daily or lifetime campaign budget, in whole currency units.

name?string

Meta and Reddit. Rename the campaign.

Lengthlength <= 255
platformSpecificData?

Meta only. Platform implied by the platform body param, same convention as POST /v1/ads/create.