Skip to content
Splashify Pro
Docs

Click-to-WhatsApp Ads

The ctwa command (alias: meta-ads) mirrors /settings/ctwa. It wraps three sub-surfaces:

  1. OAuth code exchange — finishing the Meta "Connect" flow on the backend after the browser-side OAuth dance returns a code.
  2. Conversion API (CAPI) — the dataset + event trigger config that pushes lead and purchase events back to Meta for ad attribution.
  3. Ads listing — the per-account ads inventory + per-ad detail (read-only).

Backed by /api/v1/app/meta-ads/*.

Quick start

bash
# 1. Status — has CAPI been wired up yet?
splashify ctwa                                  # default = capi status

# 2. Connect Meta (browser does the OAuth dance, paste the code here)
splashify ctwa exchange-code --code AQB0Lg…JaYHFq8KQ

# 3. Configure CAPI events
splashify ctwa capi save \
  --lead-enabled true \
  --lead-trigger "form_submitted" \
  --lead-tag "lead" \
  --purchase-enabled true \
  --purchase-trigger "order_placed" \
  --purchase-tag "buyer" \
  --purchase-currency INR

# 4. Test-fire a lead event for one contact
splashify ctwa capi send-event --event-type lead --phone +919876543210

# 5. See ads under your connected account
splashify ctwa ads
splashify ctwa ad <ad_id>

How the CTWA wiring works

text
┌─────────────┐   1. OAuth dance         ┌─────────────────┐
│   You       │ ───────────────────────► │ Meta business   │
│ (browser)   │   (in business.facebook  │ (graphical)     │
└──────┬──────┘    .com)                  └────────┬────────┘
       │                                            │
       │   2. redirect with ?code=…                 │
       ▼                                            │
┌─────────────┐   3. ctwa exchange-code            ▼
│  splashify  │ ───────────────────────► ┌─────────────────┐
│     CLI     │                          │ partnersapi     │
└──────┬──────┘ ◄─────────────────────── │ /meta-ads/*     │
       │         4. tokens stored        └────────┬────────┘
       │                                          │
       ▼                                          │
┌─────────────┐                                   ▼
│  ctwa capi  │                          ┌─────────────────┐
│  save / send│ ───────────────────────► │  Meta Graph API │
└─────────────┘   conversion events       └─────────────────┘

The CLI handles steps 3, 4, and 5. Step 1 still requires a real browser (Meta requires you to authenticate on business.facebook.com).

Command tree

text
ctwa                                  show CAPI status (default)
ctwa capi                             show CAPI config
ctwa capi save                        update CAPI config
ctwa capi send-event                  manually fire a conversion event (test)
ctwa exchange-code --code <code>      finish the OAuth handshake
ctwa refresh-token                    refresh the stored Meta token
ctwa ads                              list ads on the connected Meta account
ctwa ad <ad_id>                       show one ad

OAuth code exchange

After clicking Connect Meta in the browser, Meta redirects to your callback URL with ?code=…. Copy that code and run:

bash
splashify ctwa exchange-code --code AQB0Lg…JaYHFq8KQ
splashify ctwa exchange-code --code AQB0… \
                             --granted-scopes '["ads_management","pages_show_list"]' \
                             --redirect-uri "https://app.splashifypro.com/settings/ctwa/callback"

The backend exchanges the code for a long-lived token, encrypts it, and stores it. CAPI commands work after this succeeds.

Refresh the stored token

bash
splashify ctwa refresh-token

The CLI resolves :user_id from /app/me automatically — you don't pass it. Useful when CAPI calls start failing with token-expiry errors.

CAPI — Conversion API

CAPI sends conversion events to Meta for ad attribution. Two event types are supported:

View the config

bash
splashify ctwa capi                             # default: GET the config
splashify ctwa capi status

Response shape:

json
{
  "success": true,
  "capi": {
    "dataset_id":              "<meta_dataset_id>",
    "lead_event_enabled":      true,
    "lead_event_trigger":      "form_submitted",
    "lead_event_tag":          "lead",
    "purchase_event_enabled":  true,
    "purchase_event_trigger":  "order_placed",
    "purchase_event_tag":      "buyer",
    "purchase_event_currency": "INR",
    "purchase_event_value":    0,
    "connected":               true
  }
}

Save the config

bash
# First-time save — leave --dataset-id empty so the backend auto-creates one on Meta
splashify ctwa capi save \
  --lead-enabled true \
  --lead-trigger "form_submitted" \
  --lead-tag "lead" \
  --purchase-enabled true \
  --purchase-trigger "order_placed" \
  --purchase-tag "buyer" \
  --purchase-currency INR \
  --purchase-value 0

Only the fields you pass are sent — the rest stay unchanged.

Send a test event

bash
# Lead
splashify ctwa capi send-event --event-type lead --phone +919876543210

# Purchase with value
splashify ctwa capi send-event \
  --event-type purchase \
  --phone +919876543210 \
  --value 1499 \
  --currency INR

Useful for verifying your dataset_id + triggers are working before waiting on a real signal.

Ads inventory

bash
splashify ctwa ads                         # list ads on the connected account
splashify ctwa ad <ad_id>                  # one ad in detail

:user_id is auto-resolved from /app/me.

Common workflows

One-time CAPI bootstrap

bash
# 1. Verify Meta is connected
splashify ctwa | jq '.capi.connected'

# 2. Save the config (let the backend auto-create the dataset)
splashify ctwa capi save \
  --lead-enabled true --lead-trigger "form_submitted" --lead-tag "lead" \
  --purchase-enabled true --purchase-trigger "order_placed" \
  --purchase-tag "buyer" --purchase-currency INR

# 3. Test
splashify ctwa capi send-event --event-type lead --phone +919876543210

# 4. Then watch /events in Meta Events Manager appear

Fire purchase events from a script

bash
# After an order placed in your e-commerce backend
splashify ctwa capi send-event \
  --event-type purchase \
  --phone "$CUSTOMER_PHONE" \
  --value "$ORDER_TOTAL" \
  --currency INR

Audit which ads are running on your account

bash
splashify ctwa ads | jq '.ads[] | {ad_id, name, status, daily_budget}'

Pause CAPI without disconnecting Meta

bash
splashify ctwa capi save --lead-enabled false --purchase-enabled false

Troubleshooting

exchange-code returns 400 "Invalid code" — codes are single-use and expire within minutes. Restart the OAuth dance from the browser to get a fresh code.

exchange-code returns 400 "Required scopes missing" — the user declined a scope during the OAuth flow. Re-run the browser dance and accept all requested scopes (ads_management, pages_show_list, and the CAPI-related scopes).

capi save returns 503 "Meta not connected" — run splashify ctwa exchange-code --code <code> first.

capi save auto-create dataset returns 500 — Meta's Graph API returned an error. Verify the Meta business has CAPI enabled (business.facebook.com → Events Manager → Data Sources). Pre-create the dataset there, then pass --dataset-id <id> to skip auto-create.

capi send-event returns 200 but Meta Events Manager doesn't show it — Meta deduplicates events; the same phone + event combination within ~60s only counts once. Wait or use a different phone for testing.

refresh-token returns 401 — the stored token is unrecoverable (usually the user revoked the app on facebook.com → Apps and websites). Re-run exchange-code with a fresh code.

See also

  • splashify subscription — confirms CAPI/CTWA is on your plan.
  • splashify contacts — set the --lead-tag / --purchase-tag values on contacts manually for testing.
  • splashify expenses — per-message billing for the CTWA-triggered conversions (events are free, but the WhatsApp template they trigger is metered).