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.
Authorization
bearerAuth API key authentication: send your Zernio API key in the Authorization header, prefixed with Bearer.
In: header
Header Parameters
Optional client-generated unique key (e.g. a UUID) that makes retries safe. Same key + same body replays the original response; same key + different body → 422; key still processing → 409. Only 2xx responses are stored, so a request that failed with a 4xx can be retried with a corrected body under the SAME key.
length <= 255Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
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.createAdCampaign({ body: { accountId: 'account_abc123', adAccountId: 'adaccount_abc123', name: 'Example', goal: 'engagement', },});console.log(data);{ "validateOnly": true, "adAccountId": "act_757082720485182", "campaignId": "", "objective": "OUTCOME_APP_PROMOTION", "status": "VALIDATED"}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.
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.