Zernio
Zernio
API Reference

Campaigns and Ads

Overview

Get campaign treeGETGet daily account metricsGET

Campaigns

List campaignsGETCreate a standalone campaignPOSTUpdate a campaignPUTDuplicate a campaignPOSTDelete a campaignDELETEPause or resume a campaignPUTPause or resume many campaignsPOSTAttach extension assets to a Google Search campaignPOST

Ad Sets

Live ad-set details incl. learning phaseGETUpdate an ad setPUTDuplicate an ad setPOSTDelete an ad setDELETEPause or resume a single ad setPUTList Search keywordsGET

Ads

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

Other

Add Search keywords to an ad groupPOSTCreate a standalone ad groupPOSTCreate a Google Ads portfolio bid strategyPOSTRead a campaign's current biddingGETRead a Google campaign's device, location, and language targetingGETList ad setsGETList Google Ads portfolio bid strategiesGETList campaign-level negative keywordsGETRemove a Search keywordDELETEReplace campaign-level negative keywordsPUTPause or enable a Search keywordPATCHUpdate a Google Ads portfolio bid strategyPATCHEdit a Google campaign's device, location, or language targetingPUT
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources
Campaigns and Ads

List campaigns

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).


PlatformsMetaGoogleTikTokLinkedInPinterestX
GET
/v1/ads/campaigns

Authorization

bearerAuth
AuthorizationBearer <token>

API key authentication - use your Zernio API key as a Bearer token

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"
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)

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

Social 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

Response Body

application/json

application/json

application/json

{  "campaigns": [    {      "platformCampaignId": "string",      "platform": "facebook",      "campaignName": "string",      "status": "active",      "reviewStatus": "in_review",      "platformCampaignStatus": "string",      "campaignIssuesInfo": [        {}      ],      "adCount": 0,      "budget": {        "amount": 0,        "type": "daily"      },      "campaignBudget": {        "amount": 0,        "type": "daily"      },      "budgetLevel": "campaign",      "isBudgetScheduleEnabled": false,      "currency": "string",      "metrics": {        "spend": 0,        "impressions": 0,        "reach": 0,        "clicks": 0,        "ctr": 0,        "cpc": 0,        "cpm": 0,        "engagement": 0,        "conversions": 0,        "allConversions": 0,        "costPerConversion": 0,        "actions": {          "property1": 0,          "property2": 0        },        "actionValues": {          "property1": 0,          "property2": 0        },        "purchaseValue": 0,        "roas": 0,        "costPerAction": {          "property1": 0,          "property2": 0        },        "outboundClicks": 0,        "outboundClicksCtr": 0,        "inlineLinkClicks": 0,        "inlineLinkClickCtr": 0,        "uniqueClicks": 0,        "uniqueCtr": 0,        "videoPlayActions": 0,        "video30SecWatchedActions": 0,        "videoThruplayWatchedActions": 0,        "videoP25WatchedActions": 0,        "videoP50WatchedActions": 0,        "videoP75WatchedActions": 0,        "videoP95WatchedActions": 0,        "videoP100WatchedActions": 0,        "videoAvgTimeWatchedActions": 0,        "costPerThruplay": 0,        "funnel": {          "landingPageViews": 0,          "contentViews": 0,          "searches": 0,          "wishlistAdds": 0,          "cartAdds": 0,          "checkoutsInitiated": 0,          "paymentInfoAdds": 0,          "purchases": 0,          "leads": 0,          "registrationsCompleted": 0,          "appInstalls": 0,          "messagingConversationsStarted": 0,          "messagingFirstReplies": 0        },        "engagementBreakdown": {          "postEngagement": 0,          "pageEngagement": 0,          "reactions": 0,          "comments": 0,          "shares": 0,          "saves": 0,          "pageLikes": 0,          "videoViews": 0,          "linkClicks": 0        },        "lastSyncedAt": "2019-08-24T14:15:22Z"      },      "platformAdAccountId": "string",      "platformAdAccountName": "string",      "accountId": "string",      "profileId": "string",      "advertisingChannelType": "string",      "platformObjective": "string",      "optimizationGoal": "string",      "bidStrategy": "LOWEST_COST_WITHOUT_CAP",      "bidAmount": 0,      "roasAverageFloor": 0,      "promotedObject": {        "custom_event_type": "string",        "pixel_id": "string",        "page_id": "string"      },      "earliestAd": "2019-08-24T14:15:22Z",      "latestAd": "2019-08-24T14:15:22Z"    }  ],  "pagination": {    "page": 0,    "limit": 0,    "total": 0,    "pages": 0  }}
Was this page helpful?

Get daily account metrics

Returns daily aggregate metrics across all ads in a SocialAccount as a single time series — one row per calendar day in the requested range. 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) — same convention as `/v1/ads/tree` and `/v1/ads`. Date range defaults to the last 90 days. Capped at 730 days. Ranges older than the ingested history return a `202` immediately with the covered part and `backfillPending: true` while the rest is backfilled in the background; repeat the request shortly until it returns 200 with full data. 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 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 only `budgetType: lifetime`, Google only `budgetType: daily`). 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`. TikTok campaigns are created without a status and report `ENABLE`. Created `PAUSED` unless `status: ACTIVE` where the platform supports it. **Idempotency:** send an `Idempotency-Key` header to make retries safe.