Zernio
Zernio
PlatformsMeta Ads

Build

CampaignsAd SetsCreativesCreative LibraryPreviews

Target

TargetingCustom Audiences

Ad types

Boost a PostCreative TestingConversion CampaignsCatalog AdsMessaging & Call AdsClick-to-WhatsApp AdsLead Gen FormsReach & Frequency

Measure

InsightsMeta PixelsConversions APIAd URL Tracking Tags

Operate

Duplicate & LifecycleAccount & Ops ReadsAd LibraryAd CommentsEnums, Limits & Error Codes
Dashboard
llms.txtOpenAPI
OverviewPlatformsAPI ReferenceResources

Meta Ads

Create, boost and measure Facebook and Instagram ads with the Zernio API, using classic or business login.


Create, boost and measure Facebook and Instagram ads with POST /v1/ads/create and a connected Meta Ads token. This section covers the campaign tree (campaigns, ad sets, ads, creatives), targeting and audiences, the ad types that need their own request shape, measurement (insights, pixels, conversions) and the reads you need around a running ad account. You need a connection with the ads scopes and an ad account (act_<n>) it can act on. Use an existing ad account or create one in the customer's own business portfolio. Ads are included with usage-based billing; a legacy plan without ads gets a 403 on every call here.

Quick reference

PropertyValue
HierarchyCampaign, ad set, ad (created in one call, or level by level)
Goals11 values for goal: engagement, traffic, awareness, video_views, lead_generation, lead_conversion, conversions, app_promotion, catalog_sales, page_likes, page_visits
Buying typesAUCTION (default) and RESERVED (see Reach and Frequency)
Budget levelsCBO (campaign) and ABO (ad set); reads tell you which one a campaign uses
Bid strategiesLOWEST_COST_WITHOUT_CAP, LOWEST_COST_WITH_BID_CAP, COST_CAP, LOWEST_COST_WITH_MIN_ROAS
Creative formatsSingle image, video, carousel (2 to 10 cards), dynamic creative, per-placement assets, catalog, instant form, messaging, call (see Creatives)
Call to action valuesThe callToAction enum, plus VIEW_INSTAGRAM_PROFILE and the 3 messaging CTAs on boost (see the reference)
Special ad categoriesHOUSING, EMPLOYMENT, CREDIT, ISSUES_ELECTIONS_POLITICS, FINANCIAL_PRODUCTS_SERVICES, ONLINE_GAMBLING_AND_GAMING
Image formatsJPEG, PNG (public URL or base64), max 30 MB
Video formatsMP4, MOV, max 4 GB
Ad previewsYes, Meta iframe HTML for about 60 formats, before or after create (see Previews)
Dry-run validationYes, validateOnly: true validates the whole tree and creates nothing
InsightsSynced metrics on /v1/ads/tree, live Meta queries and async report runs (see Insights)
AudiencesCustomer list, website, lookalike, engagement, saved targeting
ConversionsYes, server-side events with hashed PII, dedup, Event Match Quality and Limited Data Use
Lead formsYes, forms plus leads by webhook or polling
SchedulingYes, ad set start and end dates, editable after launch
AnalyticsYes

Before you start

Creating Meta ads needs 4 things on the Meta side: a Meta Business account with at least one ad account (act_<n>, existing or created through the API), a Facebook Page (ads publish as the Page, and Instagram placements need an Instagram professional account linked to that Page), the ads scopes on the connected account, and a pixel or dataset for any conversion-optimized goal (conversion campaigns).

An Instagram account connected with the default Instagram Login cannot run ads: that login never grants ads scopes. A facebook or metaads account must exist in the same profile, or ads calls on the Instagram accountId return 422 linked_account_required.

Meta reviews every ad. A successful create means the ad exists, not that it delivers: reviewStatus (in_review, approved, rejected, with_issues) is separate from the delivery status, and both appear on every node the tree returns.

Connect

Call GET /v1/connect/facebook/ads with profileId. Meta has two login options:

  • Classic, the default (loginMode=classic), uses the connected Facebook posting account and its token. An active parent with ads_management and ads_read can be reused without another OAuth round trip.
  • Facebook Login for Business (loginMode=business, also accepted on GET /v1/connect/instagram/ads) creates an independent metaads connection with a Business Integration System User token. No posting account is created or required. Open the returned authUrl in a browser to complete consent.

Meta needs a Page as the actor for ad creatives, so select a Page for either path when creating ads. Business login refuses a grant with no Page (no_pages_granted). Connections and billing explains which accounts each path creates and which ones bill. The connecting accounts guide covers Page selection, and the classic ads-only flow covers headless connections and scoping sync to specific ad accounts.

OAuth scopes

ScopeWhat it enables
ads_managementCreate and manage campaigns, ad sets, ads, creatives, audiences, pixels and reservations
ads_readRead ad accounts and insights
pages_manage_adsCreate, list and archive lead forms on the Page
leads_retrievalRead submitted leads from lead ads

ads_management covers campaign management, Reach and Frequency and the Business Manager list. Creating an ad account also requires business_management and business admin access. Accounts connected before ads were enabled on the team do not carry these scopes: reconnect them, and read Account health to see what a connected account was granted. The general scope rule is on the connecting accounts guide.

Find your ad account id

Ad-account operations use accountId (the connected posting or Meta Ads account) and adAccountId (the Meta ad account). Call GET /v1/ads/accounts to list the ad accounts the connection can reach. Creating a new ad account instead takes an active metaads account as accountId and the owning businessId.

import Zernio from '@zernio/node';

const zernio = new Zernio();

const { data: adAccounts } = await zernio.adaccounts.listAdAccounts({
  query: { accountId: '66b2e19d8c3f5a7e9d0b1c2d' }
});

const adAccountId = adAccounts.accounts[0].id;

Response (200):

{
  "accounts": [
    {
      "id": "act_1234567890",
      "name": "Acme",
      "currency": "USD",
      "accountStatus": 1,
      "timezoneName": "America/New_York",
      "minimumDailyBudget": 1,
      "selectable": true,
      "unusableReason": null
    }
  ]
}

accounts[].id is the adAccountId for every other call. Budgets and bids are whole units of currency (75 is $75.00 on a USD account), never cents.

Create an ad account

POST /v1/ads/accounts creates a Meta ad account in the customer's own business portfolio. Discover portfolios with GET /v1/ads/businesses, then send accountId (an active metaads connection), businessId, name, currency and timezoneId. The connection needs business_management and business admin access. System-user tokens can return an empty businesses list; supply the known business ID in that case.

timezoneId is Meta's numeric timezone ID, not an IANA name. The reference links Meta's timezone list. Use the returned adAccountId with the existing ads endpoints.

The new account has no payment method. The customer must add one in Ads Manager before ads deliver; Zernio cannot add it through the API. Meta caps how many ad accounts a business can create and may require business verification. Closing an account does not guarantee more capacity, and an ad account can never truly be deleted once created.

This call is not idempotent and Zernio never automatically retries it. After a timeout or a 502 with details.creationStatus: "unknown", check the business in Ads Manager before creating again. A 201 with connectionUpdated: false still means the account exists: follow the returned recovery instructions to reconnect with its ID and the previous scoped IDs, instead of repeating the create.

Connections and billing

A Meta Ads connection is its own account, with platform: "metaads" and its own accountId. What else exists next to it depends on how it was connected:

How it was connectedAccounts createdWhere its Pages live
Business login (loginMode=business)One metaads account with parentAccountId: null. No Facebook account is created.In the metaads account. GET /v1/accounts/{accountId}/facebook-page lists the granted Pages and selectedPageId (add refresh=true after granting more); PUT with selectedPageId changes the default Page.
Classic, from an existing Facebook accountOne metaads account whose parentAccountId is that Facebook account. If the parent already has ads_management and ads_read, no OAuth runs. Pass accountId when the profile has several Facebook accounts.In the parent Facebook account.
Classic, through OAuth with no Facebook account for the selected PageThe metaads account, plus a Facebook account for that Page with enabled: false.In that hidden Facebook account.

The hidden Facebook account is not shown in the dashboard, cannot be posted to (ACCOUNT_NOT_ENABLED_FOR_POSTING) and is not billed. GET /v1/accounts returns it with enabled: false. Connecting the same Page later through GET /v1/connect/facebook, as the same Facebook user, turns that row into a normal Facebook account with the same accountId, and from then on it bills.

A metaads account is for ads only. It cannot serve organic Facebook or Instagram Insights: the Page insights and Instagram account insights endpoints answer 400 INVALID_FIELD_VALUE for its accountId. For posting, the inbox and organic Insights on the same Page, connect it with GET /v1/connect/facebook and select-page (or connect the Instagram account). That creates a separate facebook account with its own accountId, billed on its own.

Billing counts every active account once across your team, metaads included:

  • One metaads account counts once, however many ad accounts it reaches. Running ads also meter separately per active ad (Ads pricing).
  • A Facebook Page and an Instagram account connected for posting count once each. A business-login metaads account plus the same Page connected organically is 2 accounts.
  • Hidden (enabled: false) and disconnected accounts do not count.
  • The first 2 accounts are free. Connecting another without a card on file answers 402 with code: "PAYMENT_REQUIRED" and reason: "free_tier_exceeded"; on an OAuth redirect it arrives as error=payment_required. See Payment method required.

Pricing has the rates.

A Page is missing

The Page lists (GET /v1/connect/facebook/select-page and the Pages stored on a metaads account) show exactly the Pages Meta's token grants. Zernio does not filter out Pages already connected elsewhere. A missing Page was not ticked on Meta's Page step. Meta pre-fills the previous selection, so ask the user to connect again, click "Edit previous settings" and tick the Page. When no Page is granted at all, the redirect carries error=no_facebook_pages and an error_reason (pages_permission_declined, no_pages_granted or granted_pages_not_listed), described in If it fails.

Headless connections

In the classic headless flow, the connect_token on the redirect is valid for 15 minutes. Send it as X-Connect-Token to the list and select Page calls. Business login has no headless Page step and does not accept X-Connect-Token for one: pass pageId on GET /v1/connect/facebook/ads, or change the default Page afterwards with PUT /v1/accounts/{accountId}/facebook-page.

The campaign tree

Every Meta ad lives in a 3-level tree. Each level owns different settings, and that decides which endpoint you call:

LevelOwnsPage
CampaignObjective (goal), bid strategy, spend cap, the budget on CBO campaignsCampaigns
Ad set (adSetId)Targeting, schedule, optimization goal, promotedObject, the budget on ABO campaignsAd sets
AdThe creative: headline, body, media, call to action, linkCreatives

You rarely build the tree level by level. POST /v1/ads/create creates all 3 in one call, POST /v1/ads/boost wraps an existing post the same way, and GET /v1/ads/tree reads the hierarchy back with rolled-up metrics. Which level holds the budget (CBO or ABO) decides which update endpoint accepts a budget change; the campaigns page explains budgetLevel.

Pages

Build the ads

Campaigns

Create the full tree in one call, campaign-only creates, bid strategy and reading the tree

Ad sets

Budget, status, delivery settings and the learning phase after launch

Creatives

Attach to an ad set, video, carousel, per-placement assets, Advantage+ enhancements, swap a creative

Creative library

Standalone creatives and the ad account image library

Previews

Render an ad or a draft creative as Meta renders it

Targeting

Geo, demographic and interest targeting, and how to look up ids

Audiences

Customer list, website, lookalike and engagement audiences

Boost a post

Turn a published post into an ad

Creative testing

N ads in one ad set to test variations

Conversion campaigns

Conversion goals and the promoted object

Catalog ads

Advantage+ catalog ads from a product set

Messaging and call ads

Ads that open WhatsApp, Messenger or Instagram Direct, or dial a number

Click-to-WhatsApp ads

The deprecated CTWA endpoint, kept for existing integrations

Lead forms

Create instant forms and receive leads

Reach and Frequency

Quote, reserve and buy fixed-price reserved campaigns

Measure what they did

Insights

Synced metrics, the ROAS and status fields, breakdowns, live Meta queries and report runs

Pixels

Create, share and read pixels through the tracking tags API

Conversions

Send server-side conversion events and read Event Match Quality

URL tracking tags

Read and set the click-URL parameters on an ad

Operate and look things up

Lifecycle

Dry run, pause, resume, duplicate and delete

Account reads

Change log, studies, finances, labels, budget schedules, businesses, Instagram identities, app promotion

Ad Library

Search the public ad archive

Ad comments

Read comments on ads, dark posts included

Reference

Enums, media limits, what you cannot do and Meta error codes

Common errors

3 errors are section-wide rather than endpoint-specific.

ErrorCauseFix
403 { "error": "Ads add-on required" }The team is on a legacy plan without ads, or the Meta token is missing the ads permissionsAds are included with usage-based billing; otherwise reconnect the account so the consent screen requests the ads scopes
403 ads_allowance_exceededThe team has no payment method on file and has reached its 500 free live adsAdd a card to resume creating and resuming ads
422 linked_account_requiredThe call names an Instagram account connected with Instagram Login, which never carries ads scopesConnect a facebook or metaads account on the same profile and call with its accountId

Everything below the platform boundary comes back as type: "platform_error" with Meta's own message and subcode in platformError. The reference lists the subcodes worth recognizing on sight.

Related

  • Connecting accounts: the ads-only connect flow and Page selection.
  • Facebook and Instagram: the posting accounts an ad runs as.
  • Create standalone ad: every field of the create request.
  • Webhooks for ads: lead.received and ad status events.
  • Error handling: the envelope every 4xx uses, including platform_error with Meta's own code.
Was this page helpful?

Sender IDs

Send one-way international SMS from a brand name like ZERNIO instead of a phone number, with POST /v1/sms/sender-ids and the regular send endpoint.

Campaigns

Create a Meta campaign, ad set and ad in one call, set the bid strategy and its value rule sets, and read the campaign tree back with rolled-up metrics.

On this page

Quick referenceBefore you startConnectOAuth scopesFind your ad account idCreate an ad accountConnections and billingA Page is missingHeadless connectionsThe campaign treePagesBuild the adsMeasure what they didOperate and look things upCommon errorsRelated