Skip to main content
When you pay out from a virtual account, three objects work together, each with a distinct job:
  • Recipientwhere the money goes and over which rail. The recipient’s account_type (ACH, WIRE, or WALLET) is what determines the payout rail.
  • Quotationwhat it costs. A quote prices a flow (amount, currencies, network, fees) and, when VA-bound, locks that price for redemption.
  • Payoutthe execution. POST /v1/virtual-accounts/{virtual_account_id}/payout debits the VA balance and sends the funds, using the recipient’s rail.
This guide answers the common questions about how they combine: how the rail is chosen, what happens when the balance doesn’t match the payout, and which fields a quote actually enforces at redemption. All examples use the sandbox base URL https://api.balampay.com/sandbox; in production, drop the /sandbox prefix. Every authenticated call carries both x-api-key and Authorization: Bearer <access token> (see Authentication).

The balance model

A virtual account holds a running USD balance that is the sum of its settled deposits. A payout debits an explicit amount from that balance — it is not a “sweep” of whatever happens to be there. The amount you send is the source amount debited from the VA. Fees are taken out of it, so the recipient receives amount − fees — fees are not added on top of the balance you need. The balance required to pay out is the source amount itself. (The exception is inverse_calculation, where amount is instead the recipient leg and the source debit is amount + fees.)
A VA accumulates deposits. Multiple inbound transfers each credit the balance independently once settled; you do not need a single deposit to match the payout amount. Three settled deposits of 40,40, 30, and 30leavea30 leave a 100 balance you can pay out in one request, or across several smaller payouts.

Underfunded — the payout is rejected immediately

If the available balance is less than the source amount you request, the request fails synchronously with 400 Bad Request:
The payout does not enter a pending state, is not queued, and is not auto-cancelled — it simply never gets created. A later deposit does not “complete” a rejected payout; once the balance is sufficient, submit the payout again.

Overfunded — only the requested amount is sent

A payout sends the amount you request. If the balance is larger, the excess stays in the VA balance, available for future payouts. Nothing is lost, refunded, or force-swept — you decide when and how much to move.

Choosing the rail

The payout rail comes from the recipient, not from the payout request or the quote.
1

Create a recipient with one rail

POST /v1/recipients creates a recipient with a single account_type. That value is the rail every payout to this recipient will use.
2

Reference the recipient in the payout

The payout request carries the recipient_id. Kira reads the recipient’s account_type and routes the payout over that rail — the switch is deterministic, with no fallback or priority order.
One recipient = one rail. A recipient record holds exactly one account_type. To pay the same beneficiary over a different rail (for example both WIRE and ACH), create separate recipient records and reference the recipient_id for the rail you want on each payout. GET /v1/recipients returns them as distinct entries.
WIRE payouts from virtual accounts on the austin_capital_trust bank require extra_info.memo. The receiving bank requires a transaction purpose on every wire, and Kira forwards your memo as that purpose. A payout without a memo — or with a memo that contains no processable Latin characters — is rejected with 400 Bad Request at creation. Bank wires only accept the Fedwire character set, so accented characters are transliterated before sending (for example José becomes Jose). Payout previews do not require the memo.

Quotations and the rail

A quotation prices a flow; it does not bind the execution rail. When you create a quote you can pass an account_type — but it is used only to select the correct fee schedule for the price. The rail that actually executes is still taken from the recipient at payout time. This is why a quote created with one account_type can be redeemed against a recipient on another rail: the quote pins the money (amounts, currencies, network), not the rail. If you change the rail, the fees that were priced may no longer apply — re-quote with the matching account_type so the price reflects the rail you will actually use.
A quote locks a price for a specific rail’s fee schedule. Redeeming it against a recipient on a different rail can apply a price that no longer matches that rail’s fees. Always create the quote with the same account_type as the recipient you intend to pay.

What a quote enforces at redemption

When a payout redeems a VA-bound quote (by quote_id), Kira validates that the payout matches the quote on these fields and rejects with 400 Bad Request on any mismatch: The recipient_id and the rail (account_type) are not validated against the quote — they are resolved from the recipient at payout time. See Itemized quotations for the full pricing surface and how to redeem a quote in a payout.

Putting it together

  1. Create the recipient with the rail you intend to use (account_type).
  2. Quote the flow with the same account_type so the price matches that rail.
  3. Fund the VA — one deposit or several; the balance accumulates.
  4. Pay out the amount you want, referencing the recipient_id (and quote_id if you locked a price). Kira checks the balance, validates the quote, and sends over the recipient’s rail.