Click-to-WhatsApp Ads (CTWA)
Create Meta ads (Facebook, Instagram, Messenger) that, when tapped,
open a WhatsApp chat with your business number. The ad lives on Meta’s
Marketing API surface, so the first path segment here is your Meta ad
account ID prefixed with act_ (not a WABA or phone number).
The flow is five POSTs in order:
1. Create Campaign → returns CAMPAIGN_ID
2. Create Ad Set → references CAMPAIGN_ID, returns ADSET_ID
3. Create Ad Creative → returns CREATIVE_ID
4. Create Ad → references ADSET_ID + CREATIVE_ID, returns AD_ID
5. Publish Ad → flips AD_ID's status to ACTIVEEvery step has a matching GET for read-back.
1. Create Ad Campaign
POST /api/v25.0/act_{AD_ACCOUNT_ID}/campaigns
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{
"name": "Diwali Sale 2026",
"objective": "OUTCOME_ENGAGEMENT",
"status": "PAUSED",
"special_ad_categories": []
}| Field | Notes |
|---|---|
objective | OUTCOME_ENGAGEMENT is the standard CTWA objective. Other accepted values: OUTCOME_LEADS, OUTCOME_SALES |
status | Create as PAUSED, publish later in step 5 |
special_ad_categories | Empty array unless this ad falls under credit / employment / housing / political categories |
Response — 200
{ "id": "23857890123456789" }Read back
GET /api/v25.0/{CAMPAIGN_ID}?fields=id,name,objective,status,effective_status2. Create Ad Set
POST /api/v25.0/act_{AD_ACCOUNT_ID}/adsets
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{
"name": "Diwali Sale 2026 — India 25-34",
"campaign_id": "23857890123456789",
"daily_budget": 100000,
"billing_event": "IMPRESSIONS",
"optimization_goal": "CONVERSATIONS",
"promoted_object": {
"page_id": "{PAGE_ID}",
"whatsapp_phone_number": "+919876543210"
},
"targeting": {
"geo_locations": { "countries": ["IN"] },
"age_min": 25,
"age_max": 34
},
"status": "PAUSED",
"start_time": "2026-10-01T00:00:00+0530"
}| Field | Notes |
|---|---|
daily_budget | Lowest currency unit (paise / cents). 100000 = ₹1,000/day |
optimization_goal | CONVERSATIONS for CTWA |
promoted_object.whatsapp_phone_number | The number the ad routes to. Must be a registered WhatsApp Business number on your account |
targeting | Meta Marketing API targeting spec — geo, age, interests, custom audiences |
Response — 200
{ "id": "23857890234567890" }Read back
GET /api/v25.0/{ADSET_ID}?fields=id,name,campaign_id,daily_budget,status,effective_status,optimization_goal,promoted_object,targeting3. Create Ad Creative
POST /api/v25.0/act_{AD_ACCOUNT_ID}/adcreatives
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{
"name": "Diwali Sale 2026 — Creative v1",
"object_story_spec": {
"page_id": "{PAGE_ID}",
"link_data": {
"message": "Diwali offer — 30% off, tap to chat!",
"link": "https://wa.me/919876543210?text=I%27d%20like%20to%20know%20more",
"image_hash":"<hash from /act_{ID}/adimages upload>",
"call_to_action": {
"type": "WHATSAPP_MESSAGE",
"value": { "app_destination": "WHATSAPP" }
}
}
}
}The link is a wa.me URL — Meta optimises it as a CTWA destination.
image_hash comes from uploading an image to
/act_{AD_ACCOUNT_ID}/adimages (one extra step not strictly part of
the 5-step flow).
Response — 200
{ "id": "23857890345678901" }Read back
GET /api/v25.0/{CREATIVE_ID}?fields=id,name,object_story_spec,image_hash4. Create Ad
POST /api/v25.0/act_{AD_ACCOUNT_ID}/ads
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{
"name": "Diwali Sale 2026 — Ad 1",
"adset_id": "23857890234567890",
"creative": { "creative_id": "23857890345678901" },
"status": "PAUSED"
}Response — 200
{ "id": "23857890456789012" }Read back
GET /api/v25.0/{AD_ID}?fields=id,name,adset_id,creative,status,effective_status5. Publish Ad (flip to ACTIVE)
POST /api/v25.0/{AD_ID}
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{ "status": "ACTIVE" }Response — 200
{ "success": true }Once effective_status flips to ACTIVE (a few seconds after this
call), the ad starts serving. Inbound messages from users who tap
through include a referral block in your webhook — see
Send Messages — webhook fan-out for
the payload shape.
Errors
| Status | Body | When |
|---|---|---|
400 | (#100) Invalid parameter | Missing required field at any step; check the Meta Marketing API field reference for the exact constraint |
400 | (#200) Permissions error | Your ad account lacks ads_management permission, or the WhatsApp number isn’t linked to the Page |
400 | (#1487749) Insufficient funds | Ad account has no active payment method or balance |
403 | id does not belong to your account | The act_<AD_ACCOUNT_ID> isn’t linked to a customer under your partner account |
cURL — full 5-step flow
# 1) Campaign
CAMP_ID=$(curl -s -X POST \
"https://api.splashifypro.com/api/v25.0/act_$AD_ACCOUNT_ID/campaigns" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Diwali 2026",
"objective": "OUTCOME_ENGAGEMENT",
"status": "PAUSED",
"special_ad_categories": []
}' | jq -r .id)
# 2) Ad Set
ADSET_ID=$(curl -s -X POST \
"https://api.splashifypro.com/api/v25.0/act_$AD_ACCOUNT_ID/adsets" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"name\":\"India 25-34\",
\"campaign_id\":\"$CAMP_ID\",
\"daily_budget\":100000,
\"billing_event\":\"IMPRESSIONS\",
\"optimization_goal\":\"CONVERSATIONS\",
\"promoted_object\":{\"page_id\":\"$PAGE_ID\",\"whatsapp_phone_number\":\"+919876543210\"},
\"targeting\":{\"geo_locations\":{\"countries\":[\"IN\"]},\"age_min\":25,\"age_max\":34},
\"status\":\"PAUSED\",
\"start_time\":\"2026-10-01T00:00:00+0530\"
}" | jq -r .id)
# 3) Creative — assumes you've already uploaded the image to /act_$AD_ACCOUNT_ID/adimages
CREATIVE_ID=$(curl -s -X POST \
"https://api.splashifypro.com/api/v25.0/act_$AD_ACCOUNT_ID/adcreatives" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"name\":\"Diwali Creative v1\",
\"object_story_spec\":{
\"page_id\":\"$PAGE_ID\",
\"link_data\":{
\"message\":\"Diwali offer — 30% off!\",
\"link\":\"https://wa.me/919876543210\",
\"image_hash\":\"$IMAGE_HASH\",
\"call_to_action\":{\"type\":\"WHATSAPP_MESSAGE\",\"value\":{\"app_destination\":\"WHATSAPP\"}}
}
}
}" | jq -r .id)
# 4) Ad
AD_ID=$(curl -s -X POST \
"https://api.splashifypro.com/api/v25.0/act_$AD_ACCOUNT_ID/ads" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"name\":\"Diwali Ad 1\",
\"adset_id\":\"$ADSET_ID\",
\"creative\":{\"creative_id\":\"$CREATIVE_ID\"},
\"status\":\"PAUSED\"
}" | jq -r .id)
# 5) Publish
curl -X POST \
"https://api.splashifypro.com/api/v25.0/$AD_ID" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "status": "ACTIVE" }'Notes
- Ad account must be linked to a customer under your partner
account before these endpoints work — until that link exists, the
act_<AD_ACCOUNT_ID>resolves to 403. Contact support to onboard an ad account. - CTWA attribution comes through on inbound message webhooks as
a
referralblock withsource_type: "ad",source_id, andctwa_clid. Persistctwa_clidon first contact — it’s the join key for downstream conversion attribution. - Targeting + budget follow Meta Marketing API semantics — detailed targeting docs live with Meta, not here.