Sending
Form submissions
When a template carries a WhatsApp Flow, the person filling it in sends their answers back to you. Every submission is kept, announced by the flow.completed webhook, and readable here with any files they uploaded.
How a submission reaches you
- You send a template with a flow button, with an optional
template.flow.tokenof your own. See Send a message. - They open the form in WhatsApp, fill it in and submit.
- We record it, match it to the message that carried the form, and POST
flow.completedto your endpoint. - The same record is here, for reading back, catching up after downtime, or fetching an uploaded file.
Every endpoint on this page needs the flow_responses:read scope. It is separate from messages:read on purpose: the answers are whatever your customers typed, and a key that only sends or checks delivery should not be able to read them.
List them
curl "https://sendrixbackend.exebee.com/v1/flow_responses?flow_token=lead-8812" \
-H "Authorization: Bearer sk_live_..."{
"object": "list",
"data": [
{
"id": "frs_7c2d4e1a-0b3f-4c5d-9e6f-1a2b3c4d5e6f",
"object": "flow_response",
"message_id": "msg_2a9c1f7e-4d3b-4a8e-b1c2-3d4e5f6a7b8c",
"source_message_id": "msg_c16cead6-8385-481f-9e2e-e146d51f2738",
"template_id": "tpl_cb9182c4-6e22-4095-bd26-a61c9f8d7fba",
"flow_id": "1019982851061063",
"flow_token": "lead-8812",
"from": "919833663235",
"response": {
"screen_0_Full_name_0": "Asha Verma",
"screen_0_City_1": "Pune",
"photo_picker": [
{ "id": "3631120727156756", "file_name": "IMG_5237.jpg", "mime_type": "image/jpeg", "sha256": "..." }
]
},
"files": [
{ "index": 0, "field": "photo_picker", "file_name": "IMG_5237.jpg", "mime_type": "image/jpeg" }
],
"created_at": "2026-09-15T12:50:44.000Z"
}
],
"limit": 50, "offset": 0, "total": 1, "has_more": false
}Newest first.
| Parameter | Effect |
|---|---|
flow_token | Only submissions carrying this token. The usual way to find the one for your own record. |
source_message_id | Only submissions from forms that message carried. |
template_id | Only submissions from forms sent with that template. |
flow_id | Only submissions to that flow, by Meta's flow id. |
created_after, created_before | ISO 8601 times. Handy for catching up on everything since your endpoint was last up. |
limit, offset | Paging. Up to 100 per page. |
The fields
| Field | Means |
|---|---|
message_id | The inbound message the submission arrived as, in the person's conversation. |
source_message_id | The message that carried the form. Null when it cannot be traced, for example a form sent outside Sendrix. |
flow_token | Yours if you set template.flow.token. Otherwise one we made, starting sxf_. |
response | The answers, keyed exactly as the flow names its fields. The token is taken out. |
files | Files uploaded in the form. index is what you pass to fetch one. |
Read one
curl https://sendrixbackend.exebee.com/v1/flow_responses/frs_7c2d4e1a-0b3f-4c5d-9e6f-1a2b3c4d5e6f \
-H "Authorization: Bearer sk_live_..."The same shape as one entry in the list. The id is the one in the flow.completed webhook, so a receiver can read the full record straight from the event.
Fetch an uploaded file
curl https://sendrixbackend.exebee.com/v1/flow_responses/frs_7c2d4e1a-0b3f-4c5d-9e6f-1a2b3c4d5e6f/files/0 \
-H "Authorization: Bearer sk_live_..."{
"object": "file_link",
"file_name": "IMG_5237.jpg",
"mime_type": "image/jpeg",
"url": "https://...",
"expires_at": "2026-09-15T13:05:44.000Z"
}url downloads the file and works for fifteen minutes. Ask again for a fresh one. It is not the file itself, so the response is small whatever the upload was.
Errors
| Code | Status | Means |
|---|---|---|
insufficient_scope | 403 | The key does not hold flow_responses:read. |
not_found | 404 | No submission with that id in this workspace, or no file at that index. |
upstream_unavailable | 502 | WhatsApp would not hand over the file, most often because it is past 30 days. |
Every code is listed on Errors.