Skip to main content

Submissions

Reading and creating submissions: the canonical submission record, as JSON or CSV.

📄️List a flow's submissions

Every submission on this flow as the canonical submission record, oldest-updated first. Paginated with an opaque cursor: follow `next_cursor` until `has_more` is false. `?format=csv` (or `Accept: text/csv`) returns every matching submission as a single CSV download instead — unpaginated by contract, so `limit`/`after` together with it are a 400. 404s for a flow this key cannot see — either it does not exist, or it belongs to another organisation and the caller has no submissions on it. Requires the `submissions:read` scope.

📄️Create a submission

Creates a submission born `completed` with `initiated_by: 'api'` and runs the same after-effects a WhatsApp completion runs: notifications, the webhook, forwarding to a connected ODK or FHIR server, Sheets, the live Data tab, and the flow's record action when it has one (the response's `record_id` names the record). The contact goes through the doorway WhatsApp respondents use: matched by phone or created with consent `unknown`; the API can never assert opt-in. Answer keys are validated against the flow's current published Flow JSON; values are stored as given. `Idempotency-Key` is required: same key and body replay the stored response as 200 with `Idempotent-Replayed: true`; a different body or path under the same key is 422; the same key while the first attempt runs is 409. A retry after a timeout or a 5xx is safe with the same key. Every write happens in one transaction, so a 4xx writes nothing: an update-mode flow whose record cannot be resolved from the answer at its record key is 422 `record_not_resolved`, safe to retry with the same key once the record exists. No `Location` header is set; the record's `id` names it. The body is capped at 262144 bytes (256 KB). 404s for a flow that is not this organisation's. Requires the `submissions:write` scope; a replayed 200 spends the write bucket like any POST.