Part 5 of 7 · Chargeback responder series ~7 min read

How a response gets filed on time

Filing the right packet is worth nothing if it lands a day late, so this post is about time. It walks through the deadline watch — the one-off scheduled job armed the moment the dispute is caught — the owner-approval and auto-file modes that decide how much happens without you, and the guard underneath both: a hard cutoff that files the assembled, real-evidence packet before the deadline so a forgotten tap can never turn a winnable case into a default loss.

Key takeaways

  • The deadline watch is a one-off EventBridge Scheduler job, armed the moment the dispute was caught.
  • Two modes: auto-file (strong packets file themselves) or owner-approval (nothing files until you tap).
  • Underneath both sits a deadline guard that fires a safe margin before the bank’s due-by.
  • If nothing has been filed and you haven’t chosen to accept the loss, the guard files the assembled packet.
  • It never files late, and it never files a packet you’ve told it to drop — the deadline can’t beat you.

The watch that was armed at the front door

Back in Part 2, the very first thing the intake did after recording the deadline was arm a one-off EventBridge Scheduler job — an at(...) rule timed for a safe margin before the processor’s due_by, targeting the deadline-guard Lambda. That job is the spine of this whole post. It exists from the second the dispute is caught, before any evidence is gathered, before any packet is built. Everything else in the filing step is about giving the owner a chance to decide — but the watch is the promise that whatever the owner does or doesn’t do, the case will be filed before the cutoff or deliberately dropped, never simply forgotten.

Two modes: how much happens without you

How a case reaches the processor depends on a single setting. In owner-approval mode, the assemble step emails the owner a summary — amount, reason code, the winnability read, and the buttons — and nothing is filed until they tap File. This is the default for businesses that want a human eye on every response. In auto-file mode, a packet the assembler rated strong is filed automatically as soon as it’s ready, and the owner’s email becomes a heads-up rather than a gate; only mixed and weak cases wait for a decision. This suits higher volumes where most disputes are clear-cut and the owner only wants to be pulled in on the judgement calls. Either mode can be set per-account and overridden per dispute.

The owner’s three buttons land on a Function URL, the same signed, single-use-token pattern used across the series so a forwarded email link can’t be replayed. File submits the assembled packet now. Hold pauses for a closer look — useful when the owner wants to add a note or check something — but, crucially, Hold does not disarm the deadline guard. Accept loss records the decision not to fight and disarms the guard, so the case is closed cleanly and nothing files.

A timeline from dispute received to filed, with the deadline guard as a backstop A horizontal timeline runs left to right across the diagram, from day zero on the left to the bank’s evidence due-by on the right, with a marked safety cutoff a short margin before the due-by. Along the timeline, events are placed in order. At day zero: dispute received, deadline recorded, and the one-off EventBridge Scheduler deadline-guard job armed. Shortly after: evidence gathered and the packet assembled, and the owner emailed a summary with File, Hold, and Accept-loss buttons. Above the timeline, a happy path: the owner taps File, and cbr-file submits the packet through the processor API well before the cutoff. Below the timeline, the backstop path: the owner does not respond. When the timeline reaches the safety cutoff, the armed Scheduler job fires the deadline-guard Lambda, which checks the case is neither filed nor marked accept-loss and then files the assembled packet through cbr-file — still before the due-by. A separate small note shows that an Accept-loss tap disarms the guard so nothing files. After filing, a later marker shows the processor posting dispute closed, recorded as won or lost. A bottom note reads: the guard guarantees a winnable case is filed before the cutoff whether or not anyone taps a button. day 0 safety cutoff due_by Dispute received deadline recorded, guard job armed Packet assembled owner emailed: File / Hold / Accept Owner taps File cbr-file submits, well early No response → guard fires Scheduler triggers deadline-guard; files assembled packet before due_by later: dispute closed won / lost The guard files a winnable case before the cutoff whether or not anyone taps a button — never late.
Fig 5. The filing timeline. The deadline-guard job is armed at day zero; the owner can file early, but if no one responds the Scheduler fires the guard at the safety cutoff and files the assembled packet — always before the bank’s due-by.

The deadline guard: a backstop, not a guess

When the one-off Scheduler job fires at the safety cutoff, the deadline-guard Lambda doesn’t blindly submit something. It reads the case state and decides: if the dispute is already filed, it does nothing. If the owner chose accept loss, it does nothing — that was a deliberate decision, and the guard never overrides it. If the assembler rated the case weak and auto-file isn’t on, it does nothing but raise a last-call alert, because filing a hopeless packet just burns the fee. But if the case is winnable, assembled, and simply un-actioned — the owner was busy, on holiday, asleep — the guard files the assembled packet. The reasoning is blunt: a real-evidence packet filed at the last safe moment beats a guaranteed default loss every time. Before the cutoff the guard also triggers a re-gather if a piece (like a delivery confirmation) was still pending earlier, so it files the freshest evidence available.

Filing through the API, exactly once

Filing itself is the cbr-file Lambda calling the processor’s evidence-submission API with the key from Secrets Manager — either the assembled fields and attachments or the packet PDF, whichever this processor takes. Two cases must not file the same dispute twice — the owner tapping File a moment before the guard fires, say — so filing is guarded by an idempotency key tied to the dispute id and a conditional state transition: the case moves to filed only from ready, and a second attempt finds it already filed and stops. On a successful submit, the state, the submission id the processor returns, and the timestamp are written to the disputes table; the deadline-guard job, if it hasn’t already fired, is deleted so it can’t act on a closed case.

Tracking the outcome

Weeks later the processor posts charge.dispute.closed with the result. That webhook comes in the same verified front door, and the system records won or lost against the case — closing the loop so every dispute has a final state, and feeding the monthly summary that reports your win rate by reason code. A lost case isn’t a system failure: some disputes are genuinely the customer’s to win, which is exactly why the winnability read and the accept-loss path exist. What the system guarantees isn’t that you win every chargeback — it’s that you never lose one to a deadline you forgot.

Design rules for filing on time

  • The deadline guard is armed at intake and is the backstop for everything — the case can’t lapse.
  • Auto-file or owner-approval is a setting; in both, a winnable case still gets filed before the cutoff.
  • Hold doesn’t disarm the guard; only an explicit Accept-loss does. Inaction never becomes a silent loss.
  • Filing is idempotent — a conditional state transition means a dispute is never submitted twice.
  • The guard never files a case marked accept-loss, and never files a hopeless packet just to file something.
All posts