Create standalone ad
Creates a paid ad with custom creative across Meta, Google Ads, Pinterest, TikTok, X/Twitter, and LinkedIn. Supports three mutually-exclusive request shapes selected by the body, a legacy single-creative shape (all platforms, default), a Meta-only multi-creative shape via the creatives array (one ad set with N ads sharing budget and targeting), and a Meta-only attach shape via adSetId (adds one new ad to an existing ad set). Per-platform required fields, budget minimums, and video-ad rules are documented on each property below. LinkedIn creates a Single Image or Single Video Ad backed by a Direct Sponsored Content "dark post" authored by a Company Page (see `organizationId`); supported goals are engagement, traffic, awareness, and video_views (video ads use the `video` field; video_views requires a video), and traffic ads require `linkUrl`.
API key authentication - use your Zernio API key as a Bearer token
In: header
length <= 255Required on legacy + multi-creative shapes. Inherited from the ad set on the attach shape. Available goals vary by platform. Meta-specific: conversions requires promotedObject.pixelId + promotedObject.customEventType; app_promotion requires promotedObject.applicationId + promotedObject.objectStoreUrl; lead_generation accepts an optional promotedObject.pageId (auto-filled from the connected Page when omitted). TikTok-specific: conversions (website-conversion ad group) requires promotedObject.pixelId (your TikTok Pixel ID) and accepts an optional promotedObject.customEventType (a TikTok optimization_event code like ON_WEB_ORDER, INITIATE_ORDER, ON_WEB_REGISTER, FORM); to inherit a pixel + event from an existing ad group, pass adSetId instead. LinkedIn-specific: engagement, traffic, awareness, and video_views are supported for standalone ads (creates a Direct Sponsored Content single image or single video ad). traffic requires linkUrl; video_views requires the video field. For lead_generation / conversions on LinkedIn — or to promote an existing post — use POST /v1/ads/boost.
"engagement" | "traffic" | "awareness" | "video_views" | "lead_generation" | "conversions" | "app_promotion"Required on legacy + multi-creative shapes. Inherited on attach.
Required on legacy + multi-creative shapes. Inherited on attach.
"daily" | "lifetime"Required for Meta, Google, Pinterest, and LinkedIn on legacy + attach shapes (skip for multi-creative — use creatives[].headline). Ignored for TikTok and X/Twitter. Max: Meta=255, Google=30, Pinterest=100, LinkedIn=400. On LinkedIn this is the ad's headline (the bold text on the creative); for traffic ads it's the link card title.
Google Display only — defaults to headline if omitted. On LinkedIn, reused as the optional secondary description text on traffic (link) ads; omitted if not provided.
length <= 90Required on legacy + attach shapes. For X/Twitter this is the tweet text (max 280 chars including a ~24-char URL when linkUrl is set). On LinkedIn this is the post commentary (the intro text shown above the ad). Max: Google=90, Pinterest=500.
Required on legacy + attach shapes for Meta. Honoured on TikTok (passes through to the Spark Ad creative's call_to_action) and on LinkedIn (the CTA button on the ad; defaults to LEARN_MORE when linkUrl is set). LinkedIn accepts: LEARN_MORE, SIGN_UP, DOWNLOAD, SUBSCRIBE, REGISTER, JOIN, ATTEND, REQUEST_DEMO, VIEW_QUOTE, APPLY, SEE_MORE, SHOP_NOW, BUY_NOW. Ignored by Google, Pinterest, and X/Twitter.
"LEARN_MORE" | "SHOP_NOW" | "SIGN_UP" | "BOOK_TRAVEL" | "CONTACT_US" | "DOWNLOAD" | "GET_OFFER" | "GET_QUOTE" | "SUBSCRIBE" | "WATCH_MORE" | "REGISTER" | "JOIN" | "ATTEND" | "REQUEST_DEMO" | "VIEW_QUOTE" | "APPLY" | "SEE_MORE" | "BUY_NOW"Required on legacy + attach shapes (skip for multi-creative). On LinkedIn it's the ad's destination URL; required for traffic ads, optional for engagement / awareness.
uriImage creative for Meta/Google/Pinterest/LinkedIn on legacy + attach shapes (mutually exclusive with video). Required for LinkedIn ads unless video is set. Not required for Google Search campaigns. For TikTok, this field carries the VIDEO URL (the TikTok ads endpoint is video-only; the field retains the imageUrl name for cross-platform consistency). Ignored for X/Twitter. For Google Display, treated as the landscape image (alias of images.landscape); supply images.square alongside or the request is rejected. For LinkedIn the image is uploaded to LinkedIn under the authoring Company Page (see organizationId); recommended ratio 1.91:1 (e.g. 1200×627).
uriGoogle Display (Responsive Display Ads) only. Google RDA requires both a landscape (1.91:1) and a square (1:1) marketing image; sending only one is rejected upstream as 'Too few.' (NOT_ENOUGH_*_MARKETING_IMAGE_ASSET). Supply both URLs here. Either this field or the legacy imageUrl can provide the landscape, but square has no legacy counterpart so it must be set here for Display.
Meta (facebook, instagram) and LinkedIn. When set, creates a VIDEO ad on the legacy (or, for Meta, attach) shape. Mutually exclusive with imageUrl. For Meta multi-creative, set video per entry inside creatives[] instead. For LinkedIn the video is uploaded to LinkedIn under the authoring Company Page (see organizationId) and the campaign format is set to SINGLE_VIDEO; LinkedIn ignores thumbnailUrl (it auto-generates the poster frame) — supply MP4 H.264/AAC, 3s-30min, 75KB-500MB.
Meta-only. When present, switches to the multi-creative shape:
creates 1 campaign + 1 ad set + N ads (one per entry here).
Top-level headline / body / imageUrl / linkUrl /
callToAction are ignored in this mode. Mutually exclusive with adSetId.
1 <= itemsMeta-only. When present, switches to the attach shape: adds
one new ad to this existing ad set without creating a new
campaign. Budget, targeting, goal, schedule, AND bid strategy
are inherited from the ad set on Meta — passing bidStrategy
in attach mode returns 400. To change an existing ad set's
bid, use PUT /v1/ads/ad-sets/{adSetId}. Mutually exclusive
with creatives[].
Supported on Meta (facebook, instagram) and TikTok. On TikTok
the adSetId is the ad group ID; the new ad inherits the
ad group's bid + budget + targeting.
Google Display only
length <= 25Pinterest only. Board ID (auto-creates if not provided).
LinkedIn only. The Company Page that authors the Direct Sponsored Content ("dark") post backing the ad — accepts a numeric organization ID or a full urn:li:organization:N URN. Required unless the resolved accountId is a connected LinkedIn Company-Page account (defaults to that page) or the LinkedIn ad account is org-owned (defaults to the account's owning organization). The authenticated member must be an ADMINISTRATOR or DIRECT_SPONSORED_CONTENT_POSTER of this page (and the page must be associated with the ad account), or LinkedIn returns 403. Ignored by every other platform.
ISO 3166-1 alpha-2 country codes (e.g. ['NL']). Defaults to ['US'] when no cities or regions are provided. (LinkedIn currently honours country-level targeting only.)
Meta-only. City-level geo targeting. Each city is targeted by Meta's opaque key (the city ID) which can be looked up via GET /v1/ads/targeting/search?type=city&q=<name>&country_code=<ISO>. Optional radius + distance_unit extend the targeting beyond the city limits (e.g. radius 25 km around the city center). Both must be set together, or both omitted (Meta defaults to ~16 km when omitted).
Cannot overlap with the same country in countries (Meta returns a "locations overlap" error). Either drop the country or scope it to a different country.
Meta-only. Region-level (state/province) geo targeting. Each region is targeted by Meta's opaque key (the region ID) which can be looked up via GET /v1/ads/targeting/search?type=region&q=<name>&country_code=<ISO>.
13 <= value <= 6513 <= value <= 65Interest objects from /v1/ads/interests. Each must include id and name.
Required for lifetime budgets
date-timeCustom audience ID for targeting
Google only
"display""display" | "search"Google Search only
Google Search RSA only. Extra headlines.
Google Search RSA only. Extra descriptions.
Meta only. Controls the Advantage audience feature (targeting_automation). 0 = disabled (default), 1 = enabled. Meta Marketing API requires this field on all ad set creation requests.
0 | 1Meta only. Conversion attribution window for the ad set — maps 1:1 to Meta's
ad-set attribution_spec. Only honored for conversion goals (conversions,
lead_generation, app_promotion); ignored for awareness/traffic/engagement.
Omit to use Meta's default (7-day click + 1-day view). Meta enforces the
valid combinations: VIEW_THROUGH only allows windowDays: 1 (7d/28d view
windows were removed Jan 2026); ENGAGED_VIDEO_VIEW only 1 and only alongside
VIEW_THROUGH: 1; CLICK_THROUGH: 28 only on certain objectives. Invalid combos
surface as a Meta 400.
Example: [{ "eventType": "CLICK_THROUGH", "windowDays": 7 }, { "eventType": "VIEW_THROUGH", "windowDays": 1 }]
1 <= items <= 3Meta only. Restrict the audience by gender. 'male' targets men only, 'female' targets women only, 'all' (default) targets everyone. Ignored by non-Meta platforms.
"all""all" | "male" | "female""LOWEST_COST_WITHOUT_CAP" | "LOWEST_COST_WITH_BID_CAP" | "COST_CAP" | "LOWEST_COST_WITH_MIN_ROAS"Bid cap in WHOLE currency units (USD: 5 = $5.00; JPY: 100 = ¥100). Required when
bidStrategy is LOWEST_COST_WITH_BID_CAP or COST_CAP.
Minimum ROAS as a decimal multiplier (e.g. 2.0 = 2.0x ROAS). Required when
bidStrategy is LOWEST_COST_WITH_MIN_ROAS. Sent to Meta as
bid_constraints.roas_average_floor × 10000.
Name of the legal entity benefiting from the ad. Required by Meta when targeting EU users (DSA Article 26). Not enforced at schema level; enforced server-side when targeting intersects EU member states.
length <= 100Name of the legal entity paying for the ad. Required by Meta when targeting EU users (DSA Article 26). Note Meta API spelling: dsa_payor (not dsa_payer).
length <= 100TikTok only. Synthetic Brand Identity used when the ad
attributes to a CUSTOMIZED_USER (instead of a real TT_USER
@username). Required on the FIRST CUSTOMIZED_USER ad on a
tiktokads SocialAccount with no cached identity; omit on
subsequent ads (the identity is cached on the account after
first creation). Non-TikTok platforms ignore this field.
Alternative: configure once via PATCH /v1/connect/tiktok-ads,
then create ads without this field.
TikTok only. Forces the identity attribution on the ad:
TT_USER: the posting account's open_id (real @username branding). Requires a connected TikTok posting account on the same profile.CUSTOMIZED_USER: synthetic Brand Identity (display name + avatar). Requires a configured Brand Identity (cached on thetiktokadsSocialAccount viaPATCH /v1/connect/tiktok-ads) or an inlinebrandIdentityto create one on the fly.
When omitted, defaults to TT_USER if a posting account is
connected on this profile, else CUSTOMIZED_USER. Spark
Ads (POST /v1/ads/boost) always use TT_USER regardless
of this field — TikTok requires the original organic
post's author identity for Spark.
"TT_USER" | "CUSTOMIZED_USER"What the ad optimises against. Behaviour depends on the platform.
Meta: forwarded to the ad set's promoted_object (snake-cased).
Required for goals whose ad-set optimization_goal points at a specific
event/page/app (without it Meta rejects the ad-set create with
error_subcode: 1815430 "Please select a promoted object for your ad set"):
goal: conversions(OFFSITE_CONVERSIONS): requirespixelId+customEventTypegoal: app_promotion(APP_INSTALLS): requiresapplicationId+objectStoreUrlgoal: lead_generation(LEAD_GENERATION):pageIdis auto-filled from the connected Page when omitted
Other Meta goals (engagement, traffic, awareness, video_views) ignore this field.
TikTok: only goal: conversions uses it.
pixelIdmaps to the ad group'spixel_id. Required: a TikTok website-conversion ad group without a pixel is rejected with40002: Please select a pixel.customEventTypemaps to the ad group'soptimization_event(the pixel event to optimise for). Optional: TikTok accepts a pixel-only auto-bid conversion ad group. See thecustomEventTypefield below for the valid TikTok codes.
The remaining promotedObject.* fields are Meta-only. Platforms other than
Meta and TikTok ignore promotedObject entirely.
Response Body
application/json
application/json
import Zernio from '@zernio/node';const zernio = new Zernio({ apiKey: process.env.ZERNIO_API_KEY });const { data } = await zernio.ads.createStandaloneAd({ body: { accountId: 'account_abc123', adAccountId: 'adaccount_abc123', name: 'Example', },});console.log(data);{
"ad": {
"_id": "string",
"name": "string",
"platform": "facebook",
"status": "active",
"adType": "boost",
"goal": "engagement",
"isExternal": true,
"budget": {
"amount": 0,
"type": "daily"
},
"metrics": {
"spend": 0,
"impressions": 0,
"reach": 0,
"clicks": 0,
"ctr": 0,
"cpc": 0,
"cpm": 0,
"engagement": 0,
"conversions": 0,
"costPerConversion": 0,
"actions": {
"link_click": 160,
"post_engagement": 300,
"offsite_conversion.fb_pixel_purchase": 42
},
"actionValues": {
"offsite_conversion.fb_pixel_purchase": 2456.78,
"offsite_conversion.fb_pixel_add_to_cart": 980.5
},
"purchaseValue": 0,
"roas": 0,
"lastSyncedAt": "2019-08-24T14:15:22Z"
},
"platformAdId": "string",
"platformAdAccountId": "string",
"platformCampaignId": "string",
"platformAdSetId": "string",
"campaignName": "string",
"adSetName": "string",
"platformObjective": "OUTCOME_SALES",
"optimizationGoal": "OFFSITE_CONVERSIONS",
"platformAdAccountName": "Zernio - previously Late",
"platformCreatedAt": "2019-08-24T14:15:22Z",
"bidStrategy": "LOWEST_COST_WITHOUT_CAP",
"bidAmount": 5,
"roasAverageFloor": 2,
"promotedObject": {
"custom_event_type": "PURCHASE",
"pixel_id": "string",
"page_id": "string",
"application_id": "string",
"product_set_id": "string"
},
"creative": {
"thumbnailUrl": "string",
"imageUrl": "string",
"videoId": "string",
"videoUrl": "string",
"objectType": "string",
"objectStoryId": "string",
"effectiveObjectStoryId": "string",
"effectiveInstagramMediaId": "string",
"instagramUserId": "string",
"instagramPermalinkUrl": "string",
"mediaUrls": [
"string"
],
"body": "string",
"googleHeadline": "string",
"googleDescription": "string",
"linkUrl": "string",
"pinterestImageUrl": "string",
"pinterestTitle": "string",
"pinterestDescription": "string"
},
"targeting": {},
"schedule": {
"startDate": "2019-08-24T14:15:22Z",
"endDate": "2019-08-24T14:15:22Z"
},
"rejectionReason": "string",
"createdAt": "2019-08-24T14:15:22Z",
"updatedAt": "2019-08-24T14:15:22Z"
},
"message": "string"
}{
"error": "Unauthorized"
}Create Click-to-WhatsApp ad(s) POST
Creates one or more Click-to-WhatsApp (CTWA) ads on Meta under a single campaign and ad set. When tapped, each ad opens a WhatsApp conversation with the business attached to the supplied Facebook Page. The full hierarchy (campaign, ad set, creative(s), ad(s)) is created and activated in one call. The CTA is locked to WHATSAPP_MESSAGE and the destination is hard-coded to api.whatsapp.com/send; Meta resolves the actual WhatsApp number from the Page-to-WA pairing configured in Page settings or Business Manager. Supports two mutually-exclusive shapes: - **Single-creative**: supply top-level `headline`, `body`, and one of `imageUrl` / `video`. Creates 1 campaign + 1 ad set + 1 ad. - **Multi-creative**: supply a `creatives[]` array with N entries (each carrying its own headline, body, and image/video). Creates 1 campaign + 1 ad set + N ads sharing budget and targeting so Meta A/Bs the creatives inside a single auction instead of fragmenting budget across N parallel campaigns. Recommended when launching multiple creative variants for the same campaign. Prerequisites enforced by Meta (surfaced as platform_error on failure): the Facebook Page must be paired with a verified WhatsApp Business number, the WhatsApp Business Account must be business-verified, and the Meta access token must carry ads_management.
Get ad analytics GET
Returns detailed performance analytics for an ad. Includes summary metrics, a daily timeline over the requested date range, and optional demographic breakdowns (Meta and TikTok only). If no date range is provided, defaults to the last 90 days. Date range is capped at 730 days max.