Flows
Interactive WhatsApp forms hosted by Meta. Store the JSON definition with Tyxter, publish to Meta, and receive every end-user submission as a signed webhook.
Create
curl https://api.tyxter.com/v1/flows \
-H "authorization: Bearer $TYXTER_API_KEY" \
-H "content-type: application/json" \
-d '{
"name": "lead_capture",
"flow_json": {
"version": "6.3",
"screens": [
{
"id": "WELCOME",
"title": "Welcome",
"terminal": true,
"layout": { "type": "SingleColumnLayout", "children": [] }
}
]
}
}'We validate the JSON structurally before storage — unsupported versions, missing screens, missing terminal screens, and duplicate screen ids are rejected with 400 invalid_flow_json. Meta will do its own semantic validation at publish time.
Send
Send a published flow to a recipient with the channel-native messages route, using message.type = "flow". Address the flow with flow.action.parameters.flow_id — the published flow's provider_flow_id, which you read from GET /v1/flows/{id} once publish completes — or with flow.action.parameters.flow_name; provide exactly one. flow_token is your required opaque correlation token: it comes back to you as submission.provider_token on the flow.completed webhook, so use it to tie a completion back to your own record. flow_cta is the required button label (max 30 chars).
curl https://api.tyxter.com/v1/messages \
-H "authorization: Bearer $TYXTER_API_KEY" \
-H "content-type: application/json" \
-d '{
"channel": "whatsapp",
"sender": { "type": "whatsapp_phone_number", "id": "pn_..." },
"recipient": { "type": "phone_e164", "id": "+5511999999999" },
"message": {
"type": "flow",
"flow": {
"body": { "text": "Tap below to complete your booking." },
"action": {
"name": "flow",
"parameters": {
"flow_id": "1234567890",
"flow_token": "booking-7f3a",
"flow_cta": "Book now"
}
}
}
}
}'Publish
Snapshots the current flow_json into a new FlowVersion and enqueues the Meta sync worker. Returns 202.
Completions
When an end-user submits the flow, Meta posts the completion to our webhook receiver. We persist a FlowSubmission (idempotent onflow_token) and emit flow.completed for your customer webhook endpoints.
{
"id": "evt_...",
"type": "flow.completed",
"data": {
"flow_id": "flw_...",
"name": "lead_capture",
"status": "published",
"provider_flow_id": "1234567890",
"rejection_reason": null,
"submission": {
"id": "sub_...",
"provider_token": "flow-token-xyz",
"response": { "email": "user_at_example_dot_com", "size": "M" },
"message_id": "msg_...",
"received_at": "2026-04-27T12:05:00.000Z"
}
}
}Every flow.completed data carries the correlation fields you need to tie a submission back: flow_id (the Tyxter flw_... id), provider_flow_id (the Meta flow id the message was sent with), submission.id, submission.provider_token (the flow_token you sent), submission.response (the submitted fields), and submission.message_id.
Lifecycle events
flow.published— publish succeeded.flow.rejected— Meta rejected;rejection_reasonattached.flow.completed— end-user submitted the form.