How earnings book
Earnings are an append-only ledger. Rows are never mutated — a correction is always a new row — so a cursor walk never misses an adjustment:interchange_accrual— a charge settled;amount_cents(positive) is your share of it.interchange_reversal— a refund or return settled;amount_cents(negative) claws back exactly the share of the refunded amount. Partial refunds reverse partial shares.payout— accrued earnings were paid out (negative, no underlying network transaction). Earnings accrue as bookkeeping and pay out as USDC to your company pool address, where the deposit also shows on the pool feed.
Refunds arrive in two shapes, and the reversal row’s
transaction_id tells them apart. A standalone refund is its own transaction on the network — its row carries the refund’s id and transaction_amount_cents (negative); correlate to the original via card_id, merchant, or your order mapping. An in-place refund (the charge itself flips to refunded) mirrors its accrual exactly — its row carries the original charge’s id, so it joins straight back to the accrual, and transaction_amount_cents is null. The same network doctrine drives transaction.cleared refunds and reward.reversed.commerce_markup_accrual, funding_markup_accrual, commerce_markup_reversal, token_share_routed, token_share_reversal) appear in the same feed; they key on internal ids, so their transaction_id is null.
Earnings are separate from Tokenback routing: reward_share_bps routes a slice of your share onward to the purchasing user as tokens (at 0, you keep all of it, and no reward.* events fire).
The reconciliation feed
GET /api/v1/wallet/earnings returns the ledger newest-first, scoped to your org and your credential’s mode:
transaction_idis the settled transaction’s provider id — the same anchortransaction.clearedandreward.earnedcarry, so one key joins earnings, transactions, and rewards. It isnullonly onpayoutrows.transaction_amount_centsis the underlying settled (or refunded, negative) amount, so you can recompute the share or drive your own reward math without a second lookup.- Filter with
?kind=interchange_accrual|interchange_reversal|payout; paginate with?limit=(max 100) and?starting_after=<row id>. - Rows exist for test-mode settlements too (
livemode: falseunder a test credential) — simulated charges accrue the same way, so the reconciliation loop is rehearsable end to end.