figma guide
Designing breach settlement payment idempotency and duplicate submission prevention UI in Figma: IDMP-*, DUP-SUB-*, and safe resubmit gates
Design breach settlement payment idempotency UI in Figma with IDMP-* keys, DUP-SUB-* collision detection, resubmit previews, and audit-safe gates across SUB-*, WAVE-REX-*, and reissue flows.
- Published
- Updated
- Sep 25, 2026
- Read time
- 6 min
- Level
- Intermediate
Quick answer
Idempotency UI stops the most expensive settlement bug: two successful bank legs for one award. Design IDMP- keys* scoped to pay_id + action (SUB-* · REX-* · REISSUE-* · RECOVERY-), DUP-SUB- collision screens when operators double-click generate or replay webhooks, and resubmit preview modals that list in-flight SUB-, clearing items (CLR-EXC-*), and open TRACE-PEND- before allowing another attempt. Treasury consoles should show “effective payment state” (not just latest button click); auditors need LOG-IDMP-* proving why a second SUB-* was blocked or intentionally superseded. Pair with ACK/NACK, re-export, void/recall, and returned payment modules. Start from the Figma guides hub and use modals, inline alerts, and Dev Mode handoff.
Who this is for
- Product designers on disbursement flows where “Submit again” is the default fix for slow processors.
- Engineers implementing idempotent APIs but lacking operator-visible collision UX.
- Auditors and counsel reviewing clawback cases caused by duplicate SUB-* rather than claimant fraud.
IDMP-* key model
IdempotencyRecord — IDMP-992-8841 · scope: pay_id PAY-992-4412 · action: SUBMIT_FILE
├── Key composition (display + API):
│ ├── pay_id or batch_id · action_enum · intent_hash (FILE-NACHA-* hash or ROW-PATCH-* set)
│ ├── client_request_id (browser) · server_idempotency_key
│ └── superseded_by optional (when court-ordered replacement SUB-* allowed)
├── States:
│ ├── pending → committed | failed | superseded | blocked_duplicate
│ ├── DUP-SUB-* when second request matches committed pending leg
│ └── BLOCK-IDMP-* when void/recall or CLR-EXC-* forbids new attempt
├── Linked artifacts:
│ ├── SUB-* · SUB-ACK-* · FILE-NACHA-* ([NACHA preview](/designing-breach-settlement-payment-file-generation-and-nacha-preview-ui-in-figma/))
│ ├── WAVE-REX-* ([re-export](/designing-breach-settlement-payment-re-export-and-batch-correction-ui-in-figma/))
│ ├── REISSUE-* ([returned payment](/designing-breach-settlement-returned-payment-and-reissue-ui-in-figma/))
│ └── RECOVERY-* ([clearing exceptions](/designing-breach-settlement-ach-clearing-exception-and-settlement-failure-ui-in-figma/))
└── Audit:
├── LOG-IDMP-* every block/allow decision
└── Counsel override OVR-IDMP-* rare · requires APR-PAY-* or court doc id
| Action | Idempotency scope | Block if |
|---|---|---|
| SUB-* | FILE hash + wave | SUB-ACK pending · duplicate hash |
| WAVE-REX-* | Patched pay_id set | Same patch already in flight |
| REISSUE-* | pay_id + RET-* | Prior REISSUE committed unsettled |
| VOID-* | pay_id + SUB-* | Conflicting active TRACE-* |
| RECOVERY- batch* | recovery_plan_id | Overlapping pay_ids in pending SUB-* |
Verdict: Show operators the key and the blocking reason—hidden idempotency fails under shift handover.
DUP-SUB-* collision UX
DuplicateSubmission — DUP-SUB-992-033 · attempted_by: ops_user_44 · blocked_at: 2026-09-25T14:02Z
├── Header ([inline alert](/designing-inline-alerts-and-banners-in-figma/)):
│ ├── “This submission was already started” · severity=blocking
│ ├── Link to active SUB-* · SUB-ACK status · FILE-NACHA-* version
│ └── Do not offer “submit anyway” without OVR-IDMP-* path
├── Comparison table:
│ ├── Row: attempted now vs in-flight (hash · pay count · dollar)
│ ├── Highlight diff if operator changed BENE since first SUB-*
│ └── CTA: View [NACK queue](/designing-breach-settlement-payment-submission-acknowledgment-and-processor-nack-remediation-ui-in-figma/) · Open [payee correction](/designing-breach-settlement-payee-correction-and-beneficiary-update-ui-in-figma/)
├── Safe next steps (radio):
│ ├── Wait for SUB-ACK / TRACE-PEND-*
│ ├── Cancel in-flight via [void/recall](/designing-breach-settlement-stop-payment-void-and-in-flight-recall-ui-in-figma/) then new IDMP-*
│ ├── Create WAVE-REX-* for rejected subset only
│ └── Escalate to counsel (OVR-IDMP-*)
└── Footer: Copy idempotency key for support ticket · LOG-IDMP-* id
For double-click on “Generate NACHA,” disable button after first IDMP-* pending—show loading states on the wave card.
Resubmit preview modal (before second SUB-*)
ResubmitPreview — modal · trigger: RESUB-* or “Retry submission”
├── Effective payment state per pay_id:
│ ├── last SUB-* outcome · clearing_state · RET-* open?
│ ├── [GATE-PAY-*](/designing-breach-settlement-disbursement-hold-release-and-payment-gate-ui-in-figma/) · [FIN-AWD-*](/designing-breach-settlement-award-restatement-and-fin-awd-version-history-ui-in-figma/) version
│ └── Fraud FRD-* hold?
├── Idempotency section:
│ ├── New IDMP-* preview key · collision risk badge
│ ├── List pay_ids that will be skipped (already settled)
│ └── Dollar total of *new* legs only
├── Confirm checklist:
│ ├── ☑ Prior SUB-* terminal or superseded
│ ├── ☑ No duplicate FILE hash unless NACK cleared
│ ├── ☑ [PAY-VAL-*](/designing-breach-settlement-pre-export-payment-validation-and-exception-queue-ui-in-figma/) pass or OVR-EXC-*
│ └── ☑ Counsel APR-PAY-* if OVR-IDMP-*
└── Primary CTA: Commit RESUB-* · Secondary: Cancel
Use steppers when RESUB-* spans multiple operator roles (ops → counsel → treasury).
Comparison: idempotency vs fraud duplicate detection
| System | Question it answers | UI surface |
|---|---|---|
| IDMP-* | Did we submit twice? | DUP-SUB-* · resubmit modal |
| FRD-* | Did claimant double-claim? | Fraud prevention |
| REC-* | Does bank ledger match? | Fund reconciliation |
| FIND-* | Did QA sample fail? | Post-disbursement QA |
Best for: Training—idempotency is operational safety, not fraud scoring.
Integration across the payment pipeline
- Pre-export validation attaches intent_hash to VAL-PASS-* so SUB-* cannot drift from validated rows.
- Counsel approval stores APR-PAY-* id on IDMP-* when batch-level submit requires it.
- Bank confirm commits settlement—subsequent REISSUE-* must use new IDMP-* keys, not replay old SUB-*.
- Clawback links to LOG-IDMP-* to prove duplicate leg vs claimant error.
- Claimant timeline never displays idempotency keys—only human states from hold release notifications.
Webhook retries from processors: show read-only “duplicate webhook ignored” in SUB-ACK detail with matching IDMP-* receipt id.
Handoff checklist (Dev Mode)
- IdempotencyRecord — idmp_id (IDMP-*), scope_type_enum, scope_id, action_enum, intent_hash, state_enum, superseded_by optional.
- DuplicateSubmissionBlock — dup_sub_id (DUP-SUB-*), blocked_request_id, active_idmp_id, reason_code_enum.
- IdempotencyOverride — ovr_idmp_id (OVR-IDMP-*), idmp_id, apr_pay_id or court_doc_id, reason_text.
- IdempotencyAuditLog — log_idmp_id (LOG-IDMP-*), decision_enum, actor, correlation_id.
- ResubmitPreview — resub_preview_id, proposed_idmp_key, pay_id_list_json, skip_list_json.
Common mistakes
| Mistake | Why it hurts | Fix |
|---|---|---|
| Idempotency only on API | Ops bypass in UI | DUP-SUB-* screens |
| Key = pay_id alone | Collides SUB vs REISSUE | action_enum in key |
| “Submit anyway” button | Double pay | OVR-IDMP-* only |
| No intent_hash | Same wave, changed rows | FILE hash / patch set |
| Hide in-flight SUB-* | Repeat clicks | Disable + link |
| Webhook retries create SUB-* | Ghost attempts | Processor id on IDMP-* |
| Supersede without audit | Court discovery gap | LOG-IDMP-* + doc id |
| Claimant-triggered resubmit | Fraud vector | Admin-only RESUB-* |
Recommended workflow
- Add IDMP- badge* on every SUB-* and WAVE-REX-* row in treasury tables.
- Design DUP-SUB- as blocking modal*—not toast— with safe next-step radios.
- Build resubmit preview into NACK remediation RESUB-* path.
- Wire OVR-IDMP- to counsel queue* with APR-PAY-* attachment requirement.
- Document public_copy_key rules so portals never leak technical keys.
FAQ
Same FILE-NACHA-* hash submitted twice?
Block with DUP-SUB-* unless first SUB-* failed with FILE-NACK-* and RESUB-* policy allows supersede.
WAVE-REX-* vs full new SUB-*?
REX uses patch intent_hash · full SUB-* uses whole-file hash—preview must show non-overlapping pay_ids.
Returned payment reissue idempotency?
New IDMP- per REISSUE-** · block if prior REISSUE still in clearing (CLR-EXC-*).
Partial SUB-ACK and IDMP-*?
One IDMP- per SUB-** · partial outcomes split pay_id states—do not mint second SUB-* for accepted rows.
OVR-IDMP-* when is it allowed?
Court order · processor duplicate file acceptance · documented VOID-* completion—never for operator convenience alone.
Next steps
- Design breach settlement payment submission acknowledgment and processor NACK remediation UI in Figma — SUB-* attempts and RESUB-*
- Design breach settlement payment re-export and batch correction UI in Figma — WAVE-REX-* patch keys
- Design breach settlement ACH clearing exception and settlement failure UI in Figma — block RECOVERY-* collisions
- Design breach settlement stop payment, void, and in-flight recall UI in Figma — supersede paths
- Design breach settlement fund reconciliation and bank matching UI in Figma — prove single settlement leg
§ Keep reading