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.
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
{ "adAccountId": "string", "campaignId": "string", "objective": "string", "status": "ACTIVE"}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).
Update a campaign
Campaign-level edits. Send at least one of `budget`, `bidStrategy`, `portfolioBidStrategyId`, `name` or `platformSpecificData`. An unsupported field is always an error, never a silent drop. | Body field | Meta | Google | Others | |---|---|---|---| | `bidStrategy` | Yes | Yes | 501 | | `bidAmount`, `roasAverageFloor` | 400 (ad-set level) | Yes | 400 | | `portfolioBidStrategyId` | 400 | Yes | 400 | | `budget` (CBO; ABO returns 409) | Yes | 501 | 501 | | `name` | Yes | 501 | 501 | | `platformSpecificData.spendCap` | Yes | 400 | 400 | | `accountId` (empty campaigns) | Yes | - | - | 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`). 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. `accountId` forwards the update straight to Meta for a campaign with zero ads, which would otherwise 404; the response then carries `updated: 0`.