Outcome
Persist a point-in-time response CSV and understand its protected storage, download scope and notification effects.
POST /api/forms/{formId}/submissions/exports
Before you start
Use the intended original organization and discover a canonical Forms workspace through supported Auth resources. Bind it separately as workspace resource context. Resolve the formId through authorized forms.list/references; an input id is not a grant.
A user bearer resolves the requested workspace against actual grants; reads require read access, export creation requires read_write. API keys retain the exact Auth-verified workspace binding. Concrete application permission is workspace:read for the two reads and workspace:write for export creation.
These guides contain source-derived synthetic UNRUN examples only. No real answers, respondent identities, exports, delivery actions, notifications, models, keys or provider operations were read or executed. Public technical guidance does not publish application data.
Request
Action: app_topolo_forms.submissions.exports.create. Validate the published input and bind the discovered workspace separately. Plan the exact export creation with confirmation before any authorized mutation.
Behavior and response
This confirmed mutation reads the form and all selected-workspace submissions, unprotects response content, builds a CSV, protects csv_body under the environment policy and inserts a new forms_exports row with a fresh formexport_UUID. It does not alter the form or submissions. Creation is not idempotent: a repeat creates a new export id and can schedule another export-ready notification.
Returns HTTP201 {export:{id,filename,downloadUrl,createdAt}}. The download URL is configured FORMS_PUBLIC_BASE_URL or request origin, followed by /api/forms/{formId}/submissions/exports/{exportId}; it deliberately carries no workspace query. The URL itself grants no access: download still requires the original organization/workspace binding and workspace:read.
The CSV uses current non-layout field definitions in order, with translated Submitted at/Respondent name/Email headers and field labels. Answers for removed/unknown field ids are not extra columns. Each current field uses answerDisplayText; arrays/structured answers become display text rather than lossless typed JSON. A reserved placement-context column appears only when at least one selected submission has context.
Rows use CRLF with a final CRLF. Cells containing commas, double quotes or CR/LF are quoted and embedded quotes doubled. The selected encoder does not neutralize formula-leading spreadsheet text. Treat exported respondent content as untrusted data when opening in a spreadsheet; this guide does not certify formula safety.
The stored CSV field is protected by the environment-aware policy, while an authorized download unprotects it into plaintext. Catalog wording that the file contains readable answers is not proof that its stored bytes are unencrypted. Development does not require encryption; this action is not permission to alter key custody.
After persistence, source schedules forms.export.ready to the form creator, falling back to the actor. It skips notification without configured Notify URL/service credential or recipient. Notify errors are caught/logged; HTTP201 does not prove delivery or provider acceptance. The actual generated export id identifies that notification idempotency key, not the create request.
Form and submission reads are separate and no database snapshot transaction joins them. The persisted file is fixed after creation; later submissions/field changes need a separately approved fresh export. No stored-export deletion or exact rollback action is published. A lost HTTP response may follow successful insertion.
Scope and consistency
Original organization, verified workspace and discovered form scope the concrete read before producing these responses. Missing/out-of-scope form returns HTTP404 {error:not_found}; the response does not reveal another tenant.
Form reads and response/export/delivery queries are separate operations without a shared transaction or snapshot isolation. Protection or database failure is not an empty collection; retain actual request/status evidence instead of changing context, keys or environment policy.
Catalog structural output overlays permit generic carriers. The precise envelopes and fields described here come from the pinned handler and mapper, not that broad schema alone. Current sourceRevision matches the reviewed source; loaded runtime, key health, browser behavior and provider outcomes remain separately unproved.
Worked examples
A stored fictional CSV snapshot
Complete source-derived synthetic UNRUN HTTP201. Successful scope/write grant, readable fictional form and submissions, successful protection/storage. The fictional base URL is illustrative, not a deployed route. Notification receipt/delivery is not established.
Input:
{
"formId": "forms_docs_fixture"
}
Response:
{
"export": {
"id": "formexport_docs_fixture",
"filename": "fixture-feedback-responses.csv",
"downloadUrl": "https://forms.example.test/api/forms/forms_docs_fixture/submissions/exports/formexport_docs_fixture",
"createdAt": "2026-10-21T00:00:00.000Z"
}
}
Verify the real authorized scope and interpret only the documented response. Fictional identifiers and this example authorize no application operation.
No matching form
Complete source-derived synthetic UNRUN HTTP404. Successful original authentication/workspace/permission checks, then no matching form row. No cross-tenant probe.
Input:
{
"formId": "forms_absent_docs_fixture"
}
Response:
{
"error": "not_found"
}
Verify the real authorized scope and interpret only the documented response. Fictional identifiers and this example authorize no application operation.
Verify and recover
-
Retain the exact export.id, filename, createdAt, original scope and actual request evidence. Creation success identifies a stored snapshot, not a delivered file or notification.
-
The catalog points to submissions.exports.download for file verification, but the reviewed declaration currently describes JSON while the HTTP handler returns CSV attachment. This transport mismatch is with the source owner; do not invent a JSON/base64 carrier or run a live export merely to test the guide. Use only a subsequently qualified authorized download path.
-
If creation response is lost, stop before repeating: no export-list/idempotent-create operation is published here. Reconcile with the owner using retained request evidence. A retry may create another file/notification.
-
On actual auth/protection/database failures retain sanitized code/status/request id. Shared-runtime errors may have different carriers; failure is not an empty response or evidence of no committed export.
No automatic inverse or export deletion is published. Preserve the generated id and evidence. Never delete the form, erase an organization or replay export creation as a rollback.
Refusals
403 / forbidden: Preserve the original context and route denial; obtain legitimate access from the owner, never broaden or substitute credentials.
404 / not_found: Reconcile the discovered form and canonical workspace within the original authorized context.
Related actions
Change log
- 2026-10-21: Added exact current handler/mapper behavior, authorization and collection or mutation limits, complete synthetic response examples, verification and recovery. Source review only; examples remain unrun.