Outcome
Review reset, new-channel and all-due-row execution effects before retrying delivery processing.
POST /api/forms/{formId}/deliveries/retry
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.deliveries.retry. Validate current input, plan the exact intended mutation, bind the canonical workspace separately and confirm only the approved operation.
Input requires discovered formId andsubmissionId. Optional channels is a nonempty subset of confirmation,notification,crm,consent,outbound; omitted means allfive. After scoped form lookup, source validates a JSON body up to4000bytes, trims submissionId, verifies the submission in the sameform/org/workspace, and rejects missing submission404 submission_not_found.
It loads current settings and INSERTORIGNOREenqueues requested currentlyenabled channels that lack a row. Existing rows keep their prior protected snapshots. New rows can send an old response to a newly enabled destination using current form/settings; this is an intentional new external effect needing review, not merely retrying previously approved settings.
For requested channels, failed/skipped rows reset to pending,attempts0,nextAttemptAtnow with leases cleared. It does not clear prior lastError/detail at that reset. Delivered/accepted rows are not reset. returned retried is the number of reset rows, not created rows, attempts, successes, respondents or successful sends.
Critical scope boundary: channels filters enqueue/reset, but the subsequent runSubmissionDeliveries iterates every ledger row for that submission, not only requested channels. Other existing due pending/failed rows or expired in_progress leases can therefore run too. A caller approving only one channel must not assume channels isolates execution. Review/approve all potentially due rows or obtain owner correction before invoking.
Each run uses a database conditionalclaim, incrementsattempts and assigns a two-minute lease/token. Only due pending/failed rows or expired in_progress rows can claim; unexpired lease, delivered,accepted,skippedwithoutreset or future retry rows do not claim. Competing workers are coordinated by conditional storage, not a global external exactly-once guarantee.
The runner first requires current scoped form/submission context even for an existing snapshot, then reads that snapshot or persists a legacy snapshot fallback. It executes channel-specific ports and stores accepted/delivered/skipped/failed with conditional lease-token settlement. Context failure is recorded as failed delivery_context_unavailable with retry scheduling where possible. A missing context can become skipped submission_not_found.
Retryable failures schedule attempts up to6automaticattempts with backoff1minute,5minutes,30minutes,2hours,12hours. Manual reset returns attempts to0 and can restart that budget. No extra schedule is installed by this action; invocation of the existing cron and its loaded runtime are separate.
Notify channels, Consent updates and CRM/outbound Nexus handoffs can be external operations. CRM/outbound storedaccepted means Nexus handoff, not downstream completion. Other channel storeddelivered reflects the adapter result; it is not independently verified emailreceipt/legalconsent/businesssuccess. Detailed progress may be retained across retries.
The endpoint waits for its runner and returns HTTP200 {retried,deliveries:[...all submission rows...]}. Rows use the same11field projection as the ledger read. No success:true or new submissionid envelope is required. HTTP200 with retried0 may mean noeligiblefailed/skippedrows, accepted/deliveredterminalrows, future/leased rows, or newlyenqueuedwork; inspect actual records rather than interpreting0as no effects.
Reset, enqueue, key/snapshot work, external effects and final ledger read are separate. If response or settlement is lost, preserve uncertainty; never claim that a delivered/accepted guard proves no duplicate external effect after an interrupted pre-settlement attempt. Reconcile actual ledger and authorized downstream evidence before deciding on any further retry. No automatic inverse is published.
Worked examples
A previously accepted handoff is not reset
Complete source-derived synthetic UNRUN HTTP200. Original authorized form/submission exists, all settingsdisabled, this existing outbound row is accepted, no other due rows. No new row/reset/attempt and no provider call in the imagined case; deliveryid is fictional.
Input:
{
"formId": "forms_docs_fixture",
"submissionId": "formsub_docs_fixture",
"channels": [
"outbound"
]
}
Response:
{
"retried": 0,
"deliveries": [
{
"id": "formdelivery_docs_fixture",
"submissionId": "formsub_docs_fixture",
"channel": "outbound",
"status": "accepted",
"attempts": 1,
"lastError": null,
"detail": {
"nexusDeliveryIds": [
"delivery_docs_fixture"
]
},
"nextAttemptAt": null,
"deliveredAt": null,
"createdAt": "2026-10-20T00:00:00.000Z",
"updatedAt": "2026-10-20T00:00:01.000Z"
}
]
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
No channel rows and nothing enabled
Complete source-derived synthetic UNRUN HTTP200. Valid fictional existing submission, allcurrentchannelsdisabled, noexistingledgerrows. Empty is a successful scoped read, not a swallowed database/protection failure.
Input:
{
"formId": "forms_docs_fixture",
"submissionId": "formsub_docs_fixture"
}
Response:
{
"retried": 0,
"deliveries": []
}
Retain only actual approved scope/response evidence; fictional ids/tokens and this example authorize no live submission, retry, private read or external effect.
A reset row settles skipped from its disabled snapshot
Complete source-derived synthetic UNRUN HTTP200. One existing failed confirmation row has a readable snapshot with confirmationdisabled; no otherrows. Reset→conditionalclaim increments to1→channel_disabled skips without Notify; retaineddetail is empty. Fixed illustrative timestamp; no real attempt ran.
Input:
{
"formId": "forms_docs_fixture",
"submissionId": "formsub_docs_fixture",
"channels": [
"confirmation"
]
}
Response:
{
"retried": 1,
"deliveries": [
{
"id": "formdelivery_docs_fixture",
"submissionId": "formsub_docs_fixture",
"channel": "confirmation",
"status": "skipped",
"attempts": 1,
"lastError": "channel_disabled",
"detail": {},
"nextAttemptAt": null,
"deliveredAt": null,
"createdAt": "2026-10-20T00:00:00.000Z",
"updatedAt": "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.
Submission missing in this form and workspace
Complete source-derived synthetic UNRUN HTTP404. Form exists, auth/scope/body pass, selectedsubmissionqueryreturnsnorow beforeenqueue/reset/run.
Input:
{
"formId": "forms_docs_fixture",
"submissionId": "formsub_absent_docs_fixture"
}
Response:
{
"error": "submission_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.