Submissions
Submissions are scoped to a form. All endpoints require a bearer token with the right ability.
Base URL: https://formspring.io/api/v1
| Method | Path | Ability |
|---|---|---|
| GET | /forms/{form}/submissions |
submissions:read |
| POST | /forms/{form}/submissions/bulk |
submissions:write |
| GET | /forms/{form}/submissions/export |
submissions:export |
| GET | /forms/{form}/submissions/{submission} |
submissions:read |
| PUT | /forms/{form}/submissions/{submission} |
submissions:write |
| DELETE | /forms/{form}/submissions/{submission} |
submissions:write |
| GET | /forms/{form}/submissions/{submission}/files/{file} |
submissions:read |
List submissions
GET /forms/{form}/submissions?folder=inbox&per_page=25
Query parameters:
| Param | Values | Default | Notes |
|---|---|---|---|
folder |
inbox, spam, all |
inbox |
|
per_page |
1–100 | 25 | |
page |
integer | 1 | |
category |
string | — | Filter by AI category |
since |
ISO 8601 | — | Filter to submissions after this timestamp |
until |
ISO 8601 | — | Filter to submissions before this timestamp |
Response 200: paginated SubmissionCollection. Each entry includes id, status, category, ai_moderation, payload, received_at, plus files if the submission included uploads.
Show a submission
GET /forms/{form}/submissions/{submission}
{submission} is the submission ID (subm_...). Returns the full SubmissionResource including raw payload, parsed fields, attached files (with signed download URLs valid for 60 seconds), and metadata.
Update a submission
PUT /forms/{form}/submissions/{submission}
Content-Type: application/json
{
"payload": { "email": "fixed@example.com" },
"status": "received"
}
status accepts received, spam, processed, failed. Updating status to spam moves the submission to the spam folder; received moves it back to the inbox.
payload does a shallow merge — fields you don't include are left untouched. To clear a field, set it to null.
Response 200: updated SubmissionResource.
Delete a submission
DELETE /forms/{form}/submissions/{submission}
Hard delete. Removes the submission row, attached files, and any audit trail. Cannot be undone.
Response 200: {"ok": true}
Bulk action
POST /forms/{form}/submissions/bulk
Content-Type: application/json
{
"ids": ["subm_01H...", "subm_02H..."],
"action": "delete"
}
action is one of delete, mark_spam, mark_not_spam. Up to 500 IDs per call.
Response 200:
{ "ok": true, "affected": 47, "skipped": [] }
skipped lists IDs the caller wasn't allowed to act on (e.g. wrong team).
Export
GET /forms/{form}/submissions/export?format=csv
format is csv or json. Returns a streaming response; for large exports the response is chunked, not paginated.
| Format | Content-Type |
|---|---|
csv |
text/csv; charset=utf-8 |
json |
application/json |
The CSV includes one column per known field plus metadata columns (id, received_at, status, category, score). Files are referenced by signed URL in a _files column.
?since= and ?until= query params apply to exports too. Without them, the export covers all submissions in the form.
Download a file
GET /forms/{form}/submissions/{submission}/files/{file}
Returns a 302 Found redirect to a signed URL on object storage. The signed URL is valid for 60 seconds. Follow the redirect to actually download.
{file} is the file ID returned in the files[] array on the submission resource.
This endpoint exists so your code never needs to know the storage backend or hold a long-lived signed URL. Each request mints a fresh one.
Common errors
| Status | Meaning |
|---|---|
400 |
Bad query params (e.g. invalid folder) |
401 |
Token missing or invalid |
403 |
Token lacks required ability |
404 |
Form, submission, or file not found |
413 |
Bulk action exceeded 500 IDs |
429 |
API rate limit hit |