Click-to-WhatsApp ads
Keep an existing POST /v1/ads/ctwa integration running, and see what the newer messaging endpoint replaces it with.
Create an ad that opens a WhatsApp conversation with POST /v1/ads/ctwa.
The endpoint is deprecated and stays available for integrations that already call it. New work goes to POST /v1/ads/messaging.
You need accountId, adAccountId and a Facebook Page paired with a verified WhatsApp Business number.
Optional whatsappPhoneNumber selects a number already paired with the Page. Omitting it keeps the default pairing. The same selector is available on messaging ads.
Create the ad
The call to action is fixed to WHATSAPP_MESSAGE. The destination is fixed to https://api.whatsapp.com/send.
Meta resolves the number from the Page-to-WhatsApp pairing in your Page settings. Zernio builds the campaign, ad set, creative and ad in the one call.
import Zernio from '@zernio/node';
const zernio = new Zernio();
const { data: created } = await zernio.messagingads.createCtwaAd({
body: {
accountId: '66b2e19d8c3f5a7e9d0b1c2d',
adAccountId: 'act_1234567890',
name: 'Summer promo, WhatsApp',
headline: 'Chat with us on WhatsApp',
body: 'Get a personal quote in 2 minutes.',
imageUrl: 'https://cdn.example.com/promo.jpg',
budgetAmount: 20,
budgetType: 'daily',
currency: 'USD',
countries: ['US', 'ES']
}
});
const adId = created.ad._id;Response (201), trimmed:
{
"adType": "single",
"ad": {
"_id": "66d4a1b2c3e4f5a6b7c8d9e9",
"name": "Summer promo, WhatsApp",
"status": "pending_review",
"reviewStatus": "in_review",
"platformCampaignId": "120250000000000009",
"platformAdSetId": "120250000000000010"
},
"message": "Ad created"
}adType discriminates the response:
singlecarries onead.- A
creatives[]request returnsadType: "multi"withads[], plus the sharedplatformCampaignIdandplatformAdSetId.
To attribute conversions that happen inside the WhatsApp thread, see Conversions API for business messaging.
existingPostId or objectStoryId reuses an organic post or reel instead of a fresh creative, in place of headline / body / imageUrl / video.
See reuse an existing post on the newer endpoint for the shape. It works the same way here.
Local targeting
The endpoint accepts the full geo shape, not only countries.
For a local business, send cities, regions, zips, metros or customLocations with keys from the targeting search.
Drop the country that already contains the city. Meta rejects it as an overlap.
The ["US"] default applies only when no geo field at all is present. The request below targets Milan and nothing else.
{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "act_1234567890",
"name": "Milan local",
"currency": "EUR",
"cities": [{ "key": "2643743", "radius": 25, "distance_unit": "kilometer" }],
"dsaBeneficiary": "Acme Srl",
"dsaPayor": "Acme Srl"
}EU targeting needs dsaBeneficiary and dsaPayor unless the ad account has defaults set.
The fields are the same as on POST /v1/ads/create.
What to use instead
POST /v1/ads/messaging with destination: "whatsapp" takes the same body and the same fields.
It also covers Messenger and Instagram Direct (destination: "messenger" or "instagram_direct").
Migrating is one line: change the path and add destination. Nothing else in the request changes, so this is the same sample sent to the new endpoint:
{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "act_1234567890",
"destination": "whatsapp",
"name": "Summer promo, WhatsApp",
"headline": "Chat with us on WhatsApp",
"body": "Get a personal quote in 2 minutes.",
"imageUrl": "https://cdn.example.com/promo.jpg",
"budgetAmount": 20,
"budgetType": "daily",
"currency": "USD",
"countries": ["US", "ES"]
}The response is the same shape as above. Messaging and call ads has the full request in Node.js, Python and curl.
Both endpoints take an Idempotency-Key header. A retry with the same key replays the first response instead of creating a second campaign, ad set and ad.
See retry safely.
If it fails
A 422 means the Page is not paired with a WhatsApp number:
{
"error": "Page is not connected to a verified WhatsApp number",
"type": "invalid_request_error"
}Pair the Page with a verified WhatsApp Business number in Meta Business Manager, then retry. Meta reports the same thing as subcode 2446886.
A 403 with code: "ads_allowance_exceeded" means the team has no payment method on file and has reached its 500 free live ads.
Related
- Messaging and call ads: the endpoint that replaces this one.
- WhatsApp: the conversation side and its conversions API.
- Targeting: every geo field.
- Create messaging ad: every field of the replacement endpoint. The deprecated CTWA endpoint has no reference page.
Messaging & call ads
Create Meta ads that open a WhatsApp, Messenger or Instagram Direct conversation with POST /v1/ads/messaging, or dial a number with POST /v1/ads/call.
Reach & frequency
Quote, reserve and buy a fixed-price Meta reach and frequency campaign with POST /v1/ads/rf-predictions and buyingType RESERVED.