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

List campaigns

Lists your campaigns with spend, impressions and clicks summed across their ads, plus each campaign's status and budget.

Returns campaigns as virtual aggregations over ad documents grouped by platform campaign ID. Metrics (spend, impressions, clicks, etc.) are summed across all ads in each campaign. Campaign status is derived from child ad statuses (active > pending_review > paused > error > completed > cancelled > rejected). Google campaign budgets include amountMicros, explicitlyShared, resourceName and deliveryMethod after the next successful sync. This endpoint does not fetch Google live.

Status freshness. status, configuredStatus, platformStatus, platformAdSetStatus and platformCampaignStatus are the values Zernio last stored. Background sync refreshes them, typically within 15 to 60 minutes (Google up to about 3 hours), and ended or long-paused objects may be refreshed less often. Zernio's own status writes re-read the switches they change. A change made in the platform's own ads manager therefore shows up here only after the next sync. Controllers that act on a switch should pass live=true, which reads the switches from the platform now, stores them, and returns statusReadAt (null when the read failed and the stored values were returned). With live=true (which needs limit of 20 or less) each returned campaign's own switch (platformCampaignStatus) is read live. Live reads cover TikTok, Meta, Google, OpenAI and Reddit. The rolled-up status is not re-derived by a live read.

Budgets here are SYNCED, never read live, including with live=true. To read the current budgets (and status) of every campaign and ad set of a Meta ad account live in one call, for example as a pre-write spend gate, use GET /v1/ads/accounts/live.


PlatformsMetaGoogleTikTokLinkedInPinterestX
GET
/v1/ads/campaigns

Authorization

bearerAuth
AuthorizationBearer <token>

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

In: header

Query Parameters

includeEmpty?boolean

Meta only. Campaign reads aggregate over ad documents, so a campaign with ZERO ads is normally invisible here, the state the two-step create (campaign, then ads via existingCampaignId) leaves behind whenever Meta rejects the ad step. Set true to list those too, with adCount: 0 and zeroed metrics. Requires accountId and adAccountId, since an empty campaign has no ad row to resolve a token or ad account from.

page?integer

Page number (1-based)

Range1 <= value
Default1
limit?integer
Range1 <= value <= 100
Default20
source?string

all (default) returns both Zernio-created ads and those discovered from the platform's ad manager. Matches the web UI's default view. Pass zernio to restrict to isExternal=false only. Status is NOT filtered by default; use the status param for that.

Default"all"

Value in

  • "zernio"
  • "all"
platform?string

Value in

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

Filter by derived campaign status (post-aggregation)

Value in

  • "active"
  • "paused"
  • "pending_review"
  • "rejected"
  • "completed"
  • "cancelled"
  • "error"
adAccountId?string

Platform ad account ID (e.g. act_123 for Meta)

campaignId?string

Platform campaign ID (the platformCampaignId on each returned campaign). Returns only that campaign, or an empty list when it is not visible to the caller. Mirrors the same filter on /v1/ads and /v1/ads/tree.

pageId?string

Meta only: Facebook Page ID. Campaigns have no Page of their own, so this keeps campaigns having at least one ad backed by this Page, with adCount and metrics computed over those ads only. Mirrors the same filter on /v1/ads and /v1/ads/tree.

accountId?string

Account ID

profileId?string

Profile ID

fromDate?string

Start of metrics date range (YYYY-MM-DD, inclusive). Defaults to 90 days ago when both date params are omitted.

Formatdate
toDate?string

End of metrics date range (YYYY-MM-DD, inclusive). Defaults to today. Max 730-day range.

Formatdate
hasDelivery?boolean

Return only campaigns that delivered between fromDate and toDate: spend above zero, or impressions served at zero spend. Unlike status, which reads a campaign's CURRENT state, this filters on what happened inside the window. Filters the campaign set itself, so pagination.total counts only matching campaigns. Mirrors the same filter on /v1/ads/tree.

minSpend?number

Return only campaigns whose spend between fromDate and toDate reaches this amount, in each campaign's OWN currency (the currency field on the campaign). Implies hasDelivery; minSpend=0 applies no filter. Mirrors the same filter on /v1/ads/tree.

Range0 <= value
live?boolean

Read the on/off switches live from the platform instead of returning the synced values. The fresh values are stored (so later reads return them too) and the response carries statusReadAt, the time of the read. At most 20 platform objects are read per request. Where a read fails (credentials, platform error, no reader on that platform), the stored values come back with statusReadAt: null. See "Status freshness" in the operation description. On X the budget is read live in the same read: on GET /v1/ads/{adId} budget, adSetBudget, campaignBudget and budgetLevel are the line item and campaign budgets X holds now (stored like the switches); on the ad set and campaign listings budget is the one that line item or campaign holds now (returned, not stored); a row whose budget the other level holds keeps its synced budget.

Defaultfalse

Response Body

application/json

application/json

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.listAdCampaigns();console.log(data);
{  "campaigns": [    {      "platformCampaignId": "123456789",      "platform": "google",      "campaignName": "Search campaign",      "budget": {        "amount": 5,        "amountMicros": "5000000",        "type": "daily",        "explicitlyShared": false,        "resourceName": "customers/9122445560/campaignBudgets/1234567890",        "deliveryMethod": "STANDARD"      }    }  ],  "pagination": {    "page": 1,    "limit": 20,    "total": 1,    "pages": 1  }}
Was this page helpful?

Get daily account metrics

Returns an ads account's spend, results and other metrics day by day, ready for a daily performance chart. Returns daily aggregate metrics across all ads in a SocialAccount as a single time series, one row per calendar day and currency in the requested range (one row per day unless the account's ad accounts bill in different currencies). Use this for dashboards that draw a daily-spend or daily-conversions chart, instead of calling `/v1/ads/tree` once per day. `accountId` is required. The lookup is sibling-expanded so passing the `metaads` ID also includes ads under the linked `facebook` / `instagram` posting account (and vice-versa), the same convention as `/v1/ads/tree` and `/v1/ads`. Date range defaults to the last 90 days. Capped at 730 days. History: when an ad account connects, Zernio imports its last 90 days of metrics, so `rows` hold no data for days before that. When `accountId` or `adAccountId` resolves to a Meta ad account, a range reaching further back answers `202` with `backfillPending: true` and the covered part while the older days (up to 730 days back) are imported in the background; repeat the request until it returns 200. Other platforms never return `202`. With adAccountId set to a Google customer id this is the customer-level performance report (clicks, cost, impressions, conversions, all conversions per day).

Create a standalone campaign

Creates an empty campaign, paused, so you can add ad sets and ads to it afterwards. Creates a campaign WITHOUT its first ad set / ad, on the platform of the given `accountId`. Ad sets join it later via `existingCampaignId` on the create endpoints. Platform notes: on Meta a budget here is campaign-level (CBO) by definition; omit it for ABO (each ad set carries its own budget), and `specialAdCategories` is Meta-only (400 elsewhere); `bidStrategy` is Meta and Google (400 elsewhere), and Google also accepts `portfolioBidStrategyId` instead. Google, X and OpenAI require a budget (422 without one; OpenAI accepts daily or lifetime, Google only `budgetType: daily`). On OpenAI `goal` sets the campaign objective, and `conversions` needs an active standard conversion event on the account. On Reddit `goal` is one of traffic, awareness, conversions, video_views or lead_generation (422 otherwise) and the budget is optional: with one, the campaign uses Reddit's campaign budget optimization and carries the pixel (see `promotedObject`, which then needs `customEventType` for `conversions`), daily or lifetime (a lifetime budget needs `endDate`, 400 otherwise). `startDate` / `endDate` set the campaign's schedule and need that campaign budget (400 without one). Without a budget, each ad set carries its own budget and dates. LinkedIn creates the campaign GROUP (our campaign level) and rejects a budget, which lives on the campaign (ad set) level there; it comes back `status: DRAFT`. Created `PAUSED` (TikTok `DISABLE`) unless `status: ACTIVE` where the platform supports it. **Idempotency:** send an `Idempotency-Key` header to make retries safe.