Moving money
Every financial event in Rook is a transaction, and every movement of funds happens inside one: there is no transfer without a transaction. A transaction holds one or more immutable transfers (the movements of funds), and each transfer posts one book transfer of balanced book entries.
Card authorizations, captures, and refunds are transactions of type CARD;
Rook creates their transfers from network events. This guide covers the
transaction types you create to move money, and the ones Rook posts for
fees, interest, disputes, and rewards.
Transaction types you create
All four are created through their own endpoint and returned as a
Transaction (object transaction, type set). The id is the
transaction_id used on GET /v1/transactions/{transaction_id},
…/transfers, and …/book-transfers. They share the movement fields
(status, amount, wallet_id, financial_account_id, direction,
category, memo, events[], transfer_ids[]) and the same Money
shape: integer minor units plus an ISO 4217 currency. direction is
CREDIT or DEBIT relative to financial_account_id; amount is always
non-negative.
type | Use when | Path |
|---|---|---|
INTERNAL_TRANSFER | Both legs are financial accounts on this program | /v1/internal-transfers |
PAYMENT | You originate a payin or payout to an external bank account (ACH, RTP, FedNow) | /v1/payments |
EXTERNAL_PAYMENT | The rail ran off-platform (wire, ACH, check, or transfer) and the books need a matching transaction | /v1/external-payments |
MANAGEMENT_OPERATION | An operator posts a fee, dispute outcome, reward, adjustment, or disbursement on one financial account (single-leg) | /v1/management-operations |
GET /v1/transactions?type=… lists the same objects. Pick the type that
matches how the funds actually move: do not record an originated ACH as an
external payment, and do not use a management operation to move money
between two financial accounts.
Transaction types Rook posts for you — FEE, INTEREST, DISPUTE,
REWARD — appear on GET /v1/transactions and in the activity feed with
the same shape.
Program caps for ACH, wire, RTP, FedNow, and internal transfers live on Transfer limits.
Every creating or lifecycle POST requires Idempotency-Key. Replay of
the same method, path, and body within 24 hours returns the original
status and payload.
Shared object
status is the transaction status (one set for every type). events[] is
the transaction's lifecycle log, chronological; transfers themselves never
change. Discriminate each item on type:
type | Meaning |
|---|---|
CREATED | The request was accepted. |
SETTLED | The amount posted to the ledger. |
DECLINED | The amount never posted. |
RETURNED | An ACH return unwound a settlement. |
REVERSED | An API reverse unwound a settlement. |
RELEASED | A pending external-payment hold was dropped without posting. |
CANCELED | A pending external payment was voided. |
amount (integer minor units), result (APPROVED or
DECLINED), financial_account_id, and created_at.
Internal transfers
Move funds between two financial accounts on the program. The source
(from_financial_account_id) is debited; the destination
(to_financial_account_id) is credited. On the object,
financial_account_id equals the source and direction is DEBIT.
category selects the reason; subtype is the subtype. Valid pairs:
category | subtype |
|---|---|
TRANSFER | COLLECTION, PAYMENT |
ADJUSTMENT | BILLING_ERROR, BILLING_ERROR_REVERSAL, CORRECTION, GOODWILL |
BALANCE_OR_FUNDING | AVAILABLE_TO_RESERVE, RESERVE_TO_AVAILABLE, AVAILABLE_TO_SUSPENSE, SUSPENSE_TO_AVAILABLE |
FEE | LATE, NSF, ANNUAL, ATM, FOREIGN_TRANSACTION, FEE_REVERSAL |
REWARD | CASH_BACK, CASH_BACK_REVERSAL, PROMO, PROMO_REVERSAL |
PROGRAM_FUNDING | PROGRAM_FUNDING, PROGRAM_REPAYMENT |
400 invalid_request with param: subtype. Use TRANSFER / COLLECTION to pull
from a cardholder issuing financial account onto the program operating account. Use
BALANCE_OR_FUNDING to reclassify available, reserve, and suspense on
the same program.
Status subset: PENDING, SETTLED, DECLINED, REVERSED.
stateDiagram-v2
[] --> SETTLED: create approved
[] --> DECLINED: create declined
DECLINED --> SETTLED: retry approved
DECLINED --> DECLINED: retry declined
SETTLED --> REVERSED: reverse
create approved ──► SETTLED ── reverse ──► REVERSED
create declined ──► DECLINED ─┬─ retry approved ──► SETTLED
└─ retry declined ─► DECLINED
- Create:
POST /v1/internal-transfers - Reverse:
POST /v1/internal-transfers/{internal_transfer_id}/reverseonSETTLED - Retry:
POST /v1/internal-transfers/{internal_transfer_id}/retryonDECLINED
financial_account_id matches source or destination.
Linking bank accounts
A Payment needs a linked external bank account whose state is
ENABLED and whose verification_state is ENABLED. Link the bank
before you originate ACH. Reads return last_four and the ABA
routing_number. The full account number is never returned.
Create with POST /v1/external-bank-accounts. Send either bank
details or a processor token, not both. account_number and
processor_token are write-only.
| Body | Required fields | Typical verification_method |
|---|---|---|
| Bank details | routing_number, account_number, type (CHECKING or SAVINGS), owner, owner_type (PERSON or BUSINESS) | MANUAL, MICRO_DEPOSIT, or PRENOTE |
| Processor token | processor_token, owner, owner_type | EXTERNALLY_VERIFIED |
MICRO_DEPOSIT and PRENOTE also need address plus date_of_birth
(person) or tax_id (business). tax_id and date_of_birth are
write-only.
state is the origination lifecycle. verification_state is ownership
proof. Both must be ENABLED to originate.
state | Meaning |
|---|---|
ENABLED | May originate when verification also passed. |
PAUSED | Origination declined until unpause. |
CLOSED | Terminal. No origination. |
verification_state | Meaning |
|---|---|
PENDING | Ownership proof running (micro-deposits or prenote). |
ENABLED | Passed. |
FAILED_VERIFICATION | Rejected. Retry or change method. |
INSUFFICIENT_FUNDS | A micro-deposit could not post. Retry after the bank can accept a credit. |
stateDiagram-v2
[] --> PENDING: MICRO_DEPOSIT or PRENOTE create
[] --> ENABLED: MANUAL or EXTERNALLY_VERIFIED create
PENDING --> ENABLED: amounts match / prenote succeeds
PENDING --> FAILED_VERIFICATION: mismatch or prenote return
PENDING --> INSUFFICIENT_FUNDS: micro-deposit cannot post
FAILED_VERIFICATION --> PENDING: retry or set method
INSUFFICIENT_FUNDS --> PENDING: retry
create MANUAL / EXTERNALLY_VERIFIED ──► verification_state ENABLED
create MICRO_DEPOSIT / PRENOTE ──► PENDING ─┬─ success ──► ENABLED
├─ mismatch ─► FAILED_VERIFICATION ── retry ──► PENDING
└─ NSF ──────► INSUFFICIENT_FUNDS ── retry ──► PENDING
- Verify micro-deposits:
POST .../micro-depositswith the two
Money: integer cents plus USD). Both must match.
- Retry micro-deposits:
POST .../micro-deposits/retryposts a
- Retry prenote:
POST .../prenote/retrysends a new zero-dollar
- Set method:
POST .../verification-methodto switch onto
MICRO_DEPOSIT or PRENOTE, or to pick a new method after failure.
- Pause / unpause:
POST .../pauseandPOST .../unpausetoggle
state between ENABLED and PAUSED. They do not change
verification.
PATCH /v1/external-bank-accounts/{external_bank_account_id} updates
nickname, owner, address, and user_defined_id only. List
filters: wallet_id, owner_type, state, verification_state.
Subscribe to external_bank_account.updated for state and
verification changes.
Payments
Originate an ACH payin or payout against an external bank account that is ENABLED with
verification_state ENABLED. PAYIN credits
financial_account_id (pull from the bank). PAYOUT debits it (push
to the bank). method is ACH_NEXT_DAY, ACH_SAME_DAY, RTP, or FEDNOW. sec_code
is CCD (corporate), PPD (consumer), or WEB (internet-initiated).
category is ACH, RTP, or FEDNOW, derived from method; sec_code is null on instant rails.
Status: PENDING, SETTLED, DECLINED, RETURNED, REVERSED.
return_reason_code is a NACHA code (R01 insufficient funds, R02
wallet closed, and the rest of the closed set) when status is
RETURNED, and null otherwise.
stateDiagram-v2
[] --> PENDING: create accepted
[] --> DECLINED: create declined
PENDING --> SETTLED: ACH settles
DECLINED --> PENDING: retry
SETTLED --> RETURNED: return
SETTLED --> REVERSED: network reverse
┌─────────────────────────────────┐
create accepted ─►│ PENDING │
└──────────────┬──────────────────┘
│ ACH settles
v
SETTLED ─┬─ return ──────────► RETURNED
└─ network reverse ─► REVERSED
create declined ──► DECLINED ── retry ──► PENDING
- Create:
POST /v1/payments - Retry:
POST /v1/payments/{payment_id}/retryonDECLINED - Return:
POST /v1/payments/{payment_id}/returnonSETTLEDwithreturn_reason_code
External payments
Record a movement that originated outside Rook so balances stay
correct. category is EXTERNAL_WIRE, EXTERNAL_ACH,
EXTERNAL_CHECK, or EXTERNAL_TRANSFER. Set direction relative to
financial_account_id. effective_date is the business date
(YYYY-MM-DD).
On create, omit progress_to to leave the object PENDING. Pass
SETTLED or RELEASED to skip the hold.
Status: PENDING, SETTLED, RELEASED, CANCELED, REVERSED.
stateDiagram-v2
[] --> PENDING: create
[] --> SETTLED: create progress_to SETTLED
[] --> RELEASED: create progress_to RELEASED
PENDING --> SETTLED: settle
PENDING --> RELEASED: release
PENDING --> CANCELED: cancel
SETTLED --> REVERSED: reverse
┌─────────────────────────────────┐
create ──────────►│ PENDING │
└───┬──────────┬──────────┬───────┘
│ │ │
settle release cancel
│ │ │
v v v
SETTLED RELEASED CANCELED
│
reverse
v
REVERSED
create progress_to SETTLED ──► SETTLED
create progress_to RELEASED ──► RELEASED
- Settle:
POST .../settleposts pending funds (amountmay be a partial) - Release:
POST .../releasedrops the hold without posting - Cancel:
POST .../cancelvoids a pending record - Reverse:
POST .../reverseundoes a settlement
Management operations
Post an operator adjustment on a single financial account. Set
direction relative to that financial account. category and subtype must
match:
category | subtype |
|---|---|
MANAGEMENT_FEE | LATE, NSF, ANNUAL, ATM, FOREIGN_TRANSACTION, OTHER |
MANAGEMENT_DISPUTE | CHARGEBACK, REPRESENTMENT, WON, LOST |
MANAGEMENT_REWARD | CASH_BACK, PROMO, POINTS_REDEMPTION |
MANAGEMENT_ADJUSTMENT | GOODWILL, CORRECTION, CHARGE_OFF, WRITE_OFF |
MANAGEMENT_DISBURSEMENT | DISBURSEMENT |
PENDING, SETTLED, DECLINED, REVERSED.
stateDiagram-v2
[] --> SETTLED: create approved
[*] --> DECLINED: create declined
SETTLED --> REVERSED: reverse
create approved ──► SETTLED ── reverse ──► REVERSED
create declined ──► DECLINED
- Create:
POST /v1/management-operations - Reverse:
POST /v1/management-operations/{management_operation_id}/reverseonSETTLED
Books
Every settled transaction posts one book transfer per transfer it
holds, to the books of the financial accounts involved. A book transfer is
the collection of balanced book entries (debits and credits) one
transfer posts; book entries are never presented on their own. Read a
transaction's transfers with GET /v1/transactions/{transaction_id}/transfers,
its book transfers with GET /v1/transactions/{transaction_id}/book-transfers,
the books of a financial account with
GET /v1/financial-accounts/{financial_account_id}/books, and the book
transfers posted to them with
GET /v1/financial-accounts/{financial_account_id}/book-transfers?transaction_id=….
Activity feed
Every transaction that touches a financial account appears once on
GET /v1/financial-accounts/{financial_account_id}/activity, with
transaction_id and a category that mirrors the transaction type:
CARD, INTERNAL_TRANSFER, PAYMENT, FEE, INTEREST, DISPUTE, and
ADJUSTMENT for management operations. The feed is a view; the
transaction is the source of truth.