WhatsApp Flows
WhatsApp Flows are multi-screen interactive forms Meta hosts on your
behalf — appointment booking, lead capture, surveys, order confirmation.
You define the screens as JSON, attach the flow to a MARKETING /
UTILITY template (or send it directly as an interactive message),
and Meta renders it in the WhatsApp client.
1. Create a flow
POST /api/v25.0/{WABA_ID}/flows
Authorization: Bearer pk_live_<your-key>
Content-Type: application/jsonRequest body
{
"name": "lead_capture_v1",
"categories": ["LEAD_GENERATION"]
}| Field | Notes |
|---|---|
name | Internal name, ≤ 200 chars, unique per WABA |
categories | Array. One or more of SIGN_UP, SIGN_IN, APPOINTMENT_BOOKING, LEAD_GENERATION, CONTACT_US, CUSTOMER_SUPPORT, SURVEY, OTHER |
Response — 200
{ "id": "1234567890123456" }The returned id is the flow-id used by every other endpoint
below.
2. List flows
GET /api/v25.0/{WABA_ID}/flows
Authorization: Bearer pk_live_<your-key>Response — 200
{
"data": [
{
"id": "1234567890123456",
"name": "lead_capture_v1",
"status": "DRAFT",
"categories": ["LEAD_GENERATION"],
"validation_errors": []
}
],
"paging": { "cursors": { "before": "...", "after": "..." } }
}status is one of DRAFT, PUBLISHED, DEPRECATED, BLOCKED,
THROTTLED.
3. Get one flow
GET /api/v25.0/{FLOW_ID}?fields=id,name,status,categories,validation_errors,preview
Authorization: Bearer pk_live_<your-key>The preview field returns a temporary preview URL you can open in a
browser to walk through the flow without sending it.
4. Update flow metadata
POST /api/v25.0/{FLOW_ID}
Authorization: Bearer pk_live_<your-key>
Content-Type: application/json{
"name": "lead_capture_v2",
"categories": ["LEAD_GENERATION", "CONTACT_US"]
}5. Upload flow JSON (the screens)
POST /api/v25.0/{FLOW_ID}/assets
Authorization: Bearer pk_live_<your-key>
Content-Type: multipart/form-dataForm fields
| Field | Notes |
|---|---|
name | flow.json |
asset_type | FLOW_JSON |
file | The flow definition. See Meta’s Flow JSON schema for shape |
Response — 200
{ "success": true, "validation_errors": [] }If validation_errors is non-empty, the JSON has schema problems
(unknown component, missing route, invalid endpoint binding) and the
flow stays in DRAFT with the errors attached.
6. Publish
POST /api/v25.0/{FLOW_ID}/publish
Authorization: Bearer pk_live_<your-key>Response — 200
{ "success": true }Once published, you can send the flow via
Send Messages using
type: "interactive" + interactive.type: "flow":
{
"messaging_product": "whatsapp",
"to": "+919999999999",
"type": "interactive",
"interactive": {
"type": "flow",
"body": { "text": "Tap to book" },
"action": {
"name": "flow",
"parameters": {
"flow_message_version": "3",
"flow_id": "1234567890123456",
"flow_cta": "Book now",
"flow_action": "navigate",
"flow_action_payload": {
"screen": "WELCOME_SCREEN",
"data": { "user_name": "Aditya" }
}
}
}
}
}7. Deprecate / delete
POST /api/v25.0/{FLOW_ID}/deprecate
DELETE /api/v25.0/{FLOW_ID}
Authorization: Bearer pk_live_<your-key>Deprecating keeps the flow visible to existing recipients but blocks
new sends. Delete removes it entirely; only DRAFT flows can be
deleted.
Webhook responses
When a user completes a flow, the response screen-data lands at your
configured webhook URL as a normal message webhook with
type: "interactive" and interactive.type: "nfm_reply". The
response_json field is the user’s submitted data.
Errors
| Status | Example |
|---|---|
400 | Meta returns 400 for malformed flow JSON, unsupported component, etc. |
401 | { "success": false, "message": "unauthorized" } |
403 | { "success": false, "message": "id does not belong to your account" } |
404 | { "success": false, "message": "id not found" } |
cURL — full lifecycle
# 1) Create
FLOW_ID=$(curl -X POST \
"https://api.splashifypro.com/api/v25.0/$WABA_ID/flows" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "lead_capture_v1", "categories": ["LEAD_GENERATION"] }' \
| jq -r .id)
# 2) Upload JSON
curl -X POST \
"https://api.splashifypro.com/api/v25.0/$FLOW_ID/assets" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY" \
-F "name=flow.json" \
-F "asset_type=FLOW_JSON" \
-F "file=@/path/to/flow.json"
# 3) Publish
curl -X POST \
"https://api.splashifypro.com/api/v25.0/$FLOW_ID/publish" \
-H "Authorization: Bearer $SPLASHIFY_API_KEY"Notes
- Flow versioning is implicit — uploading new
flow.jsonto an existing flow replaces the screens. To roll back, keep your old JSON in source control and re-upload. - Endpoint-bound flows require your own HTTPS endpoint that
responds to navigation events. Configure the endpoint URL in
flow.json’srouting_model. Meta’s request signing uses your business public key; rotate that key viaPOST /api/v25.0/{PHONE_NUMBER_ID}/whatsapp_business_encryption. - Preview URLs expire after ~10 minutes — fetch a fresh one each time you need to inspect.