---
title: "Create Click-to-Call ad"
method: POST
path: "/v1/ads/call"
tags: ["Messaging Ads"]
---

# Create Click-to-Call ad

`POST /v1/ads/call`

Same shape and flow as POST /v1/ads/ctwa, but the CTA is CALL_NOW dialing `phoneNumber`
via a tel: link. The ad set is destination_type PHONE_CALL optimizing QUALITY_CALL
and the campaign objective defaults to OUTCOME_LEADS.
Supports the same single-creative and multi-creative shapes as CTWA.

## Request body

- object — In addition to the `required` list, the request must use EXACTLY ONE of the two shapes: - Single-creative: `headline`, `body`, and one of `imageUrl` / `video` (mutually exclusive). - Multi-creative: a non-empty `creatives[]` array. Top-level `headline` / `body` / `imageUrl` / `video` must NOT be set on this shape. The route enforces this at the Zod boundary; OpenAPI's `required` cannot express the OR cleanly.
  - `accountId` string, required — Facebook or Instagram SocialAccount ID.
  - `adAccountId` string, required — Meta ad account ID, e.g. `act_123456789`.
  - `name` string, required — Ad display name. Used to derive campaign / ad set names. On the multi-creative shape, each ad's Meta name gets a " #N" suffix (1-indexed) so Ads Manager shows them as a numbered batch.
  - `headline` string — Single-creative shape only. Mutually exclusive with `creatives[]`.
  - `body` string — Primary text shown above the image / video. Single-creative shape only. Mutually exclusive with `creatives[]`.
  - `imageUrl` string, uri — Image asset for single-creative shape. Mutually exclusive with `video` and with `creatives[]`. Required on the single-creative shape if `video` is not supplied.
  - `video` object — Video creative for single-creative shape. Mutually exclusive with `imageUrl` and with `creatives[]`. Required on the single-creative shape if `imageUrl` is not supplied.
    - `url` string, uri, required
    - `thumbnailUrl` string, uri, required — Required by Meta for every video creative. Used as the ad thumbnail.
  - `creatives` object[] — Multi-creative shape: N CTWA ads under one campaign + one ad set, sharing budget and targeting. Mutually exclusive with the top-level single-creative fields (`headline` / `body` / `imageUrl` / `video`). Each entry must supply its own headline, body, and exactly one of `imageUrl` / `video`.
    - `headline` string, required
    - `body` string, required — Primary text shown above the image / video.
    - `imageUrl` string, uri — Image asset. Mutually exclusive with this entry's `video`. Required if `video` is not supplied.
    - `video` object — Video creative. Mutually exclusive with this entry's `imageUrl`. Required if `imageUrl` is not supplied.
      - `url` string, uri, required
      - `thumbnailUrl` string, uri, required — Required by Meta for every video creative. Used as the ad thumbnail.
  - `adSetId` string — Attach the creatives to this EXISTING messaging ad set instead of building a campaign, so the ad set keeps its learning phase. It then owns budget, targeting and schedule, so `budgetAmount`, `budgetType`, `endDate`, `objective`, `countries`, `interests` and `audienceId` are rejected with a 400 alongside it. Its `destination_type` must match the ad's destination.
  - `budgetAmount` number — Budget amount in the ad account's currency major units (e.g. dollars for USD, not cents). Must be > 0. Required unless `adSetId` is set, where the ad set owns it.
  - `budgetType` 'daily' | 'lifetime' — Required unless `adSetId` is set.
  - `currency` string — ISO 4217 currency code matching the ad account's currency (e.g. `USD`). Optional; Meta infers from the ad account when omitted.
  - `endDate` string, date-time — ISO 8601 datetime. Required when `budgetType` is `lifetime`.
  - `countries` string[] — ISO 3166-1 alpha-2 country codes. Defaults to `["US"]` only when no other geo (`cities`, `regions`, `zips`, `metros`, `customLocations`) is supplied.
  - `cities` object[] — City-level geo targeting for local CTWA campaigns. Each entry maps to Meta's TargetingGeoLocationCity. `key` is Meta's city ID. `radius` and `distance_unit` are coupled: set both or neither. Meta enforces a minimum city radius (~17 km / 10 mi); smaller values resolve to a 0-size audience and the ad fails at launch. For a tighter catchment use customLocations (lat/lng).
    - `key` string, required
    - `radius` number
    - `distance_unit` 'mile' | 'kilometer'
  - `regions` object[] — Region / state-level geo targeting. `key` is Meta's region ID (lookupable via GET /v1/ads/targeting/search?type=region).
    - `key` string, required
  - `zips` object[] — ZIP / postal-code geo targeting. `key` is the platform's postal id resolved via /v1/ads/targeting/search.
    - `key` string, required
    - `name` string
  - `metros` object[] — DMA / metro-area geo targeting. `key` is Meta's metro id (e.g. `DMA:807`).
    - `key` string, required
    - `name` string
  - `customLocations` object[] — Point-radius geo (Meta `geo_locations.custom_locations`). Use for targeting a radius around a specific lat/long when no Meta city/region key fits. `distanceUnit` is required.
    - `latitude` number, required
    - `longitude` number, required
    - `radius` number, required
    - `distanceUnit` 'mile' | 'kilometer', required
    - `name` string
    - `address` string
  - `ageMin` integer
  - `ageMax` integer
  - `interests` object[]
    - `id` string, required
    - `name` string
  - `audienceId` string — Custom audience ID to target.
  - `placements` object — Manual ad placements on the shared ad set. Omit for automatic placements. When set, restricts delivery to the chosen surfaces, mapped onto the ad set's `targeting.{publisher_platforms, facebook_positions, instagram_positions, messenger_positions, audience_network_positions, threads_positions, whatsapp_positions, device_platforms}`. Enum membership is validated here; Meta additionally enforces co-selection rules and restricts which placements are eligible for click-to-WhatsApp ads, returning an actionable error which we surface.
    - `publisherPlatforms` string[] — Top-level platforms to deliver on. A position field below is only honoured when its parent platform is included here.
    - `facebookPositions` string[]
    - `instagramPositions` string[]
    - `messengerPositions` string[]
    - `audienceNetworkPositions` string[]
    - `threadsPositions` string[]
    - `whatsappPositions` string[]
    - `devicePlatforms` string[] — Restrict by device. Omit to deliver on both mobile and desktop.
  - `advantageAudience` 0 | 1 — Meta's Advantage+ audience expansion. `0` (default) keeps targeting strict; `1` lets Meta expand beyond the supplied targeting when its delivery system finds better matches. Always sent on CREATE (Meta requires it).
  - `objective` 'OUTCOME_ENGAGEMENT' | 'OUTCOME_SALES' | 'OUTCOME_LEADS' — Defaults to `OUTCOME_ENGAGEMENT`. `OUTCOME_SALES` and `OUTCOME_LEADS` require additional account configuration (Dataset linked to the WABA for sales) and may be rejected by Meta if missing.
  - `bidStrategy` 'LOWEST_COST_WITHOUT_CAP' | 'LOWEST_COST_WITH_BID_CAP' | 'COST_CAP' | 'LOWEST_COST_WITH_MIN_ROAS' — Meta bid strategy applied to the shared ad set. Defaults to `LOWEST_COST_WITHOUT_CAP` (auto-bid) when omitted. `LOWEST_COST_WITH_BID_CAP` and `COST_CAP` require `bidAmount`. `LOWEST_COST_WITH_MIN_ROAS` requires `roasAverageFloor`. CTWA's `optimization_goal` is fixed to `CONVERSATIONS`, but the bid strategy is independent.
  - `bidAmount` number — Whole currency units (e.g. `5` = $5.00 on a USD account). Required when `bidStrategy` is `LOWEST_COST_WITH_BID_CAP` or `COST_CAP`; rejected otherwise.
  - `roasAverageFloor` number — Decimal ROAS multiplier (e.g. `2.0` = 2.0× ROAS floor). Required when `bidStrategy` is `LOWEST_COST_WITH_MIN_ROAS`; rejected otherwise. Meta enforces its own upper bound server-side.
  - `dsaBeneficiary` string — Legal entity that benefits from the ad. Required when targeting EU users (EU DSA, Article 26). Optional if the ad account has a default beneficiary: set it once via `PATCH /v1/ads/accounts` or in Meta Ads Manager, and Meta fills it in whenever the field is omitted.
  - `dsaPayor` string — Legal entity that pays for the ad. Can differ from `dsaBeneficiary` (for example, an agency paying for a client's ads). Same rules as `dsaBeneficiary`: required for EU targeting unless the ad account has a default payor.
  - `phoneNumber` string, required — E.164 number the CALL_NOW CTA dials (e.g. +34600111222).
  - `linkUrl` string, uri, required — Website shown as the creative's link. Required: Meta rejects tel: as link_data.link; the phone number rides only the CTA.

## Response `201`

Ad(s) created and submitted for review

## Other responses

- `400` — Invalid input
- `401` — Unauthorized
- `404` — Account not found
- `422` — No Facebook Page resolved for the account

---

[API](https://skmtc.net/zernio/apis/zernio-api.md) · [All operations](https://skmtc.net/zernio/apis/zernio-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/zernio/zernio-api/versions/51932b099b2f/schema)
