Outcome
Collect a reviewed response with current validation, protected storage and explicit downstream and billing boundaries.
POST /api/forms/{formId}/submissions
Before you start
Use the original authorized organization and canonical Forms workspace discovered through supported Auth resources. Bind the workspace separately; resolve form and submission ids through authorized existing Forms reads. Never execute documentation fixtures against real resources.
Both are confirmed mutations requiring application workspace:write and a user-bearer workspace read_write grant. API keys retain the exact Auth-verified workspace resource binding. Approval must cover actual answers/subjects, destinations/recipients, privacy decisions, billing and potentially external effects, not just a technical POST.
All examples are source-derived synthetic UNRUN. No form/subject read, submission, retry, CRM/Consent/Notify/Nexus, meter, provider/model or key operation was executed. Current source/declaration matching is separate from serving-runtime and provider proof.
Request and effects
Action: app_topolo_forms.submissions.submit. Validate current input, plan the exact intended mutation, bind the canonical workspace separately and confirm only the approved operation.
The authenticated action first verifies the scoped form, then delegates to the same public collector. That collector looks up the canonical form id with statuspublished, so a draft found by the outer editor read still yields404. The published input has no workspaceId/query fields; pass resource context separately, not as an undeclared input property.
Body must be JSON and at most64000bytes. answers accepts JSON-shaped values in the action schema, but the current field definitions govern actual validation. Collector keeps known non-layout fields, normalizes types, discards unknown/omitted values, applies visibility filtering, then validates visible required and field-specific constraints. Schema-valid JSON is not proof of a valid form response.
For example, checkbox/consent true or stringtrue normalizes totrue, false/stringfalse/empty becomes omitted; visible required consent then failsmissing_required_<id>. Known multiselect expects arrays and validates options; numeric fields can normalize numbers to text; name/date-range/address/country have structured shapes. This is not an arbitrary file-upload or collection ingestion action just because JSON values are accepted.
Turnstile is verified before answer validation and spam accounting. In configured production use a real approved collector token; test-token/mock-turnstile-token are accepted only by the explicit nonproduction branch. Missing token produces400 turnstile_required; unavailable setup/token acquisition503 turnstile_unconfigured; failed/unreachableverification400 turnstile_failed/turnstile_unreachable. The source also has a configuration-absent branch; this guide does not certify deployed Turnstile configuration or recommend disabling it.
After answer validation, a D1 spam bucket uses formid+SHA256(clientIP or unknown)+fixed60secondwindow, with a read check at5followed by an upsertincrement and oldbucketcleanup. The selected read-then-write sequence does not prove a strict atomic5-request concurrency ceiling. HTTP429 rate_limited includes localized message; no Retry-After value is invented.
Spam accounting precedes placement/respondent metadata validation and protected persistence; a later refusal/failure may already consume a bucket increment. topolo_ctx is an opaque1..500character placement reference of A-Z a-z0-9 . _ ~ : -, passed unchanged or omitted. Hidden field context and placement values are caller-supplied references, not trusted identity or new authorization.
Respondent name is trimmed/nullwhenblank with maximum200characters; email is trimmed/normalized/validated and maximum254. Invalid metadata can return400 respondent_name_too_long/invalid_respondent_email. These metadata fields are separate from similarly named form answers and do not verify a person or email ownership.
Accepted normalized answers/respondent metadata/placement are protected under the environment policy. The source loads current delivery settings and prepares protected per-channel context snapshots (form fields/title,answers,settings,locale etc.). It batches the submission insert and enabled-channel ledger statements in the submissions store. Other protection/key/spam/service effects are outside that batch; no universal transaction or production key-health claim.
Each accepted call uses a fresh formsub_UUID and returns HTTP201 {submission:{id,submittedAt}}. No request idempotency token or deduplication is published. After persistence, source schedules the owner submission event, channel runner, response-threshold processor and1unit form_submissions usage emission; outcomes do not become part of the201 carrier. Lost responses may follow successful storage and external work.
Delivery snapshots can drive respondent confirmation, organization notifications, CRM/outbound Nexus handoffs and Consent decisions. The app-owned forms.submission.created event targets the form creator when configured, includes respondent metadata and hidden/placement context, and uses submission-id-based event identity. Conditional failures are caught where implemented;201 is not all-channel/provider/notification/billing-settlement proof.
Usage is attributed to the owning organization with user_idnull and submissionidrequestreference. Threshold processing checks current count, claims threshold markers before conditional Notify and does not prove receiver delivery. Read each ledger channel separately; accepted Nexus ids are handoff identities, not final recipient outcomes.
There is no safe automatic undo for collection or external effects. Form deletion or organization erasure would have much broader destructive scope and cannot recall sends, CRM/Consent/provider effects. Never use them as a submission rollback or repeat POST after uncertainty without reconciliation.
Worked examples
An accepted published-form response
Complete source-derived synthetic UNRUN HTTP201. Published fictional form has visible required long_text message; original write/resourcechecks, configured Turnstile verifier accepts this fictional placeholder, spam allows, metadatavalid, protection+batch succeed. Placeholder is not a real token. No actual downstream outcome is asserted.
Input:
{
"formId": "forms_docs_fixture",
"answers": {
"message": "Synthetic response"
},
"turnstileToken": "synthetic_valid_token_unrun"
}
Response:
{
"submission": {
"id": "formsub_docs_fixture",
"submittedAt": "2026-10-21T00:00:00.000Z"
}
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
Visible required answer is missing
Complete source-derived synthetic UNRUN HTTP400. Same fictional required message field and successfully accepted Turnstile, then validation fails before spam increment and submission batch.
Input:
{
"formId": "forms_docs_fixture",
"answers": {},
"turnstileToken": "synthetic_valid_token_unrun"
}
Response:
{
"error": "missing_required_message"
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
Configured collector requires a token
Complete source-derived synthetic UNRUN HTTP400. Published form and original authorization pass; configured verifier requires token before validation/storage.
Input:
{
"formId": "forms_docs_fixture",
"answers": {
"message": "Synthetic response"
}
}
Response:
{
"error": "turnstile_required"
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
Draft form is not a public collector
Complete source-derived synthetic UNRUN HTTP404. Outer authorized editor lookup finds the fictional draft, but delegated collector finds no matching published form. No cross-tenant probe.
Input:
{
"formId": "forms_docs_fixture",
"answers": {
"message": "Synthetic response"
},
"turnstileToken": "synthetic_valid_token_unrun"
}
Response:
{
"error": "not_found"
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
Verify and recover
-
Retain exact actual response ids,request id,original organization/workspace,approved input and timestamps. For intake use separately authorized submissions.list to match submission.id; the201 body does not echo form/workspace or downstream results.
-
Read the actual delivery ledger only when authorized. Interpret status,attempts,detail,Nexusids and per-channel snapshot effects separately; do not infer provider completion or all-channel success from HTTP200/201 or retriedcount.
-
After uncertain storage/lease/adapter/transport effects, reconcile before any repeat. Never use a fresh submission,delete/erase,settingschange or another tenant as recovery. A documentation example grants no action authority.
No safe automatic inverse is published. Preserve uncertain effects and reconcile the actual authorized records/provider outcomes with their owner before any separately reviewed retry. Broad form deletion/organization erasure cannot undo downstream sends or decisions.
Refusals
403 / forbidden: Preserve original identity/scope and actual denial; obtain legitimate write grant from its owner.
404 / not_found: Reconcile discovered form and original authorized workspace; submission intake also requires published form.
Concrete collector/retry errors are documented above. Shared auth/key/database failures retain their actual codes and request evidence; no invented universal carrier. Invalid local schema input is distinct from an actual handler refusal.
Related actions
Change log
- 2026-10-21: Added source-qualified validation and mutation order, precise response examples, non-atomic/uncertain effects, delivery-scope and provider/billing distinctions, with approved verification and no automatic inverse. Examples remain synthetic and unrun.