Start a wallet hold for a transaction
Resolves the price for the requested product and places a hold on the customer's wallet. Capture or release follow at /transaction/{id}/capture or /transaction/{id}/release. Returns 202 status="dropped" when keyed-prices policy=drop and no key matches.
Start a wallet hold for a transaction › Request Body
customer_idexternal_cost_amountExternalCostAmount + ExternalCostCurrency feed the resolver's
cost.* formula-variable namespace. Required when the resolved
price's tier expression references cost.
external_cost_currencyhold_expires_atHoldExpiresAt is the TTL of the hold the reserve creates. If
the caller doesn't capture the hold by this instant the wallet
auto-releases it. Renamed from expires_at in the shape
cleanup — the old name was ambiguous about what expires.
idempotency_keymetric_keyprice_keyproduct_idquantitysubscription_idwallet_currencyWalletCurrency optionally pins the hold to the customer's wallet in this currency. The one-wallet-per-(customer, currency) invariant (idx_wallets_customer_currency) makes the lookup unambiguous. When unset the reserve falls back to the customer's primary wallet (the row with is_primary=true). Either lookup fails with a clear DomainError when the wallet doesn't exist — no auto-routing across currencies.
Start a wallet hold for a transaction › Responses
Hold created
blocked_reasonscan_proceedexpires_atfx_rate_idhold_idresolved_currencytax_ratetax_rule_idwallet_idPhase F: cross-flow reconciliation handles. Callers persist these alongside their internal record so preview/reserve/invoice numbers can be tied back to the same tax rule and FX rate snapshot.
Ingest a usage event (fire-and-forget billing)
Accepts a single usage event or a batch ({"events": [...]}). Records the event for billing on the next invoice; does not check wallet balance, credit limits, or hold availability. Use the reserve/capture flow when up-front fund availability matters.
Ingest a usage event (fire-and-forget billing) › Request Body
customer_idexternal_cost_amountexternal_cost_currencyhold_ididempotency_keymetric_keyprice_keyM186 - required for keyed products
product_idquantitysubscription_idtimestampTimestamp is the moment the event occurred (when the customer consumed the unit). Optional — when absent or zero, the server stamps it from time.Now() at ingest. Backfill / historical imports set this explicitly to whatever the source recorded. Distinct from UsageEvent.IngestedAt, which is always the server-side ingestion instant.
wallet_currencyWalletCurrency optionally pins the event to a specific wallet. Shape parity with /reserve's wallet_currency. Validated at ingest: the wallet must exist for (customer_id, wallet_currency). NULL falls back to the customer's preferred-currency cascade at finalize — the pre-040 single-wallet path.
Ingest a usage event (fire-and-forget billing) › Responses
Created event or batch result wrapped in data envelope
Capture (settle) a wallet hold
Settles a pending hold by debiting the reserved funds. Use after the work that triggered the reserve has succeeded.
path Parameters
idHold UUID
Capture (settle) a wallet hold › Request Body
amountnil = capture full hold amount
referenceoptional capture reference
Capture (settle) a wallet hold › Responses
Wrapped in data envelope
captured_atcreated_atcurrencyexpires_atidmetric_keyorganization_idreasonreference_idreference_typeresolved_atreverse_chargestatussubscription_idSubscriptionID and MetricKey identify the usage stream this hold reserves capacity for. Set by the reserve service so the usage event ingest path can detect overlap (Phase D dedup); nil for non-subscription holds like deposits.
tax_ratetax_rule_idvoided_atwallet_idRelease a wallet hold
Releases a pending hold, returning reserved funds to available balance. Use when the work that triggered the reserve was cancelled or failed.
path Parameters
idHold UUID
Release a wallet hold › Responses
Wrapped in data envelope
captured_atcreated_atcurrencyexpires_atidmetric_keyorganization_idreasonreference_idreference_typeresolved_atreverse_chargestatussubscription_idSubscriptionID and MetricKey identify the usage stream this hold reserves capacity for. Set by the reserve service so the usage event ingest path can detect overlap (Phase D dedup); nil for non-subscription holds like deposits.
tax_ratetax_rule_idvoided_atwallet_idList unified financial transactions
Returns the org's money-movement ledger across manual payments, gateway payment attempts, wallet transactions, and credit notes - newest first, cursor-paginated. Each row is normalized into the same shape so the dashboard can mix kinds in one list.
query Parameters
limitPage size (default 25, max 100)
cursorPagination cursor
kindFilter by transaction kind (manual_payment, payment_attempt, wallet_transaction, wallet_hold, credit_note). Repeatable or comma-separated.
statusFilter by unified status (succeeded, pending, failed, refunded, voided, applied, draft). Repeatable or comma-separated.
directionFilter by money direction: in | out | internal
customer_idFilter by customer UUID
invoice_idFilter by invoice UUID (skips wallet transactions, which don't reference invoices)
occurred_afterFilter by occurred_at >= timestamp (RFC3339)
occurred_beforeFilter by occurred_at < timestamp (RFC3339)
List unified financial transactions › Responses
Paginated list with data and pagination envelope
customer_iddirectionidinvoice_idkindoccurred_atraw_idreferencesourcestatussubscription_idsummarywallet_id