1. Run a payout batch
The shape that survives contact with production: one destination per payee per attempt, an idempotency key derived so retries are distinguishable, and pacing built in.- The destination is resolved inside the loop. They are single-use and expire; one per attempt is the only correct pattern.
- The name check happens before the money. On verified routes
displayNameis the name the bank holds — a mismatch means the account number is wrong or belongs to someone else. - The intent is recorded before the call. If the process dies mid-request, you still know the reference to ask about.
2. Retry without paying twice
The rules are unusual enough to be worth stating as code.3. Watch a transfer to completion
An external transfer returnspending. Do not poll it in a loop.
4. Reconcile against the ledger
A transfer is an instruction. A transaction is what actually moved. Reconcile against the ledger, not against your own record of what you asked for.
The snapshot matters:
destination.displayName, institutionName, and accountNumberLast4 are frozen onto the transfer. Deleting a recipient afterwards does not blank your history.
5. Sweep between your own accounts
The simplest transfer there is, and useful as a health check.completed immediately, so a daily sweep is also a cheap end-to-end check that your key, accounts, and balances are all healthy.
What you cannot do here
- Cancel or amend a transfer. Once created, it is observed, not steered.
- Approve or reject one. Dashboard only.
- Transfer from a customer wallet. Wallet accounts are excluded as a source.
- Filter transfers by account or reference range. The list takes a fixed set of parameters; use transactions for anything richer.