Recovery playbook

Working a 90-day backlog of unreversed transfers

The first audit usually returns a longer list than anyone expected: dozens or hundreds of charges where the money went out and never came back. The instinct is to work it top-to-bottom by amount. That instinct wastes the window. Recoverability decays with time and payout cycles, so the ordering question is which findings are still collectible — and a disciplined per-finding workflow that leaves complete evidence behind matters more than raw speed.

Sort by recoverability, then size

Active seller with funds currently reachable comes first; payout-window cases — recently paid, likely to transact again — come next; dormant or churned accounts come last regardless of amount. The modelled arithmetic is blunt: a $60 finding against an account receiving payouts weekly is worth more expected dollars than a $400 finding against an account that churned in March. Size decides within tiers, never across them.

The per-finding workflow

Six steps, every time: verify live state against the API, compute owed from current totals, decide reverse-or-net against policy floors, execute with an idempotency key scoped to the finding, verify the balance transaction moved, mark resolved with the reversal id attached. Expect some executions to leave negative balances — that is the post-payout case, handled deliberately rather than rediscovered in panic.

const transfer = await stripe.transfers.retrieve(charge.transfer as string);
const owed = expectedReversal(charge, transfer) - (transfer.amount_reversed ?? 0);
if (owed > 2 && await isActive(transfer.destination)) {
  await reverse(transfer, owed, `recovery-${charge.id}`);
}

Batching and seller communication

Group work by seller so one proactive note summarising affected transactions replaces N silent debits. The message template is simple — what happened, what it cost whom, what we did, what changed in our code — and it converts a recovery programme from adversarial to administrative in the space of an email.

Closing the loop

A backlog worked without fixing its cause rebuilds within a quarter. Aggregate the resolved findings by cause — support-dashboard refunds, admin tools, retry queues, missing partial handling — and route the top causes to engineering. The audit’s highest-value output is that ranked list, not the recovered dollars.

What FeeGuard does about it

The historical scan produces this queue automatically with risk scores, recoverable figures and cause attribution; CSV export feeds the run; findings track open → investigating → resolved with evidence attached, so the workflow above is enforced by the tooling rather than by memory.

Common questions

How far back can we recover?

The free lookback covers 90 days, and older findings are usually balance-dead anyway — the two constraints conveniently agree.

Should we reverse everything on the list?

No. Floors, relationships and expected value all veto individual items. Working the list means deciding each one, not executing each one.