POST /v1/quotations, API version 2026-06-01) is the pricing surface for virtual-account flows. It returns a line-by-line fee breakdown — every fee as its own object with a stable code, who it is charged_by (Kira vs. your markup), and the inputs that produced it — plus the tier context and the depeg-aware conversion rate. A VA-bound quote is persisted and returns a quote_id you redeem when you create the payout, locking the price for 15 minutes.
This guide covers:
- How to engage the itemized shape (the version header).
- Creating a preview (pre-VA, ephemeral) and a VA-bound quotation (persisted, redeemable).
- Redeeming a quote in a payout.
- Migrating from the previous pricing model (
payout/preview+create_quote).
https://api.balampay.com/sandbox; in production, drop the /sandbox prefix.
Two independent axes — read this first.
- Response shape is controlled by you, via the
X-Api-Versionheader. Sending2026-06-01is what switchesPOST /v1/quotationsto the itemized envelope below. - Which pricing engine computes your fees is configured by Kira per account (a controlled rollout). The itemized shape renders whichever engine is active for your account. You do not toggle the engine from the API — contact your account manager to be enabled.
Engage the itemized shape
Every request carries the standard credentials plus the version header that selects the itemized envelope:x-api-key header and the Authorization: Bearer <access token> token from POST /auth (see Authentication).
Without
X-Api-Version: 2026-06-01, POST /v1/quotations returns the previous (aggregated) preview shape. The header is what selects the itemized envelope documented here.A. Preview — price before you have a virtual account
Usequote_for (the origin rail + currency) to price a hypothetical flow during onboarding, before any VA exists. A preview is ephemeral: quote_id is null, nothing is persisted, and it cannot be redeemed.
quote_for previews do not accept rail (top-level), payment_instructions, or from_held_balance — those are VA-bound only. Sending any of them with quote_for returns 400.B. VA-bound quotation — persisted and redeemable
Identical to a preview but keyed byvirtual_account_id. The quote is persisted, returns a quote_id, and is redeemable for 15 minutes in a subsequent payout.
Picking rail for your recipient
rail and the recipient’s account_type are two different vocabularies for the same rail — the quote names the settlement rail, the recipient names the account kind. Map from the recipient you are about to pay:
ACH maps to two rails, and the recipient does not tell you which — the same ACH recipient can be paid ACH_STANDARD or ACH_SAME_DAY, and the fixed fee differs. Choose the one you intend to settle on; the quote prices that choice.A crypto (WALLET) recipient has no bank rail — price it with target alone. On a quote_for preview, a rail/currency mismatch is rejected with 400; on a VA-bound quote it is not validated, so a stray rail is accepted and silently prices a bank-rail fee onto a crypto delivery. Omit it.Per-transaction markup override
By default your markup is configured per account and surfaces ascharged_by: "client" lines (e.g. inbound_markup). To charge a one-off markup for a single quote instead, send client_markup — it replaces your account-configured markup for that quote only.
Rules and behavior:
- At least one leg must be greater than 0. An all-zero or empty override, a
percentage_bpsabove10000, or any unknown key is rejected with400 validation_error(the body is.strict). - Engine-native units — send integers, not decimals: the flat leg in the minor units of the currency you fund with (×100 for USD, ×10⁶ for USDT/USDC) and the percentage leg in bps. Kira applies that precision shift onto the quote’s USD notional for you and performs no other conversion, so a value scaled at the wrong precision still charges the wrong amount.
- It emits up to two
charged_by: "client"lines —client_markup_fixed(the flat leg) andclient_markup_percentage(bps on the gross source) — which roll intototals.client_markup_total. - It replaces the account-configured markup for this quote: you are not also charged the configured
*_markuplines. - It is not suppressed by
transactional_waived— an explicit per-transaction instruction always applies. - On an
inversequote it is counted by the back-solve:source.amountgrosses up to cover it.
fixed_minor: 500 + percentage_bps: 50 on a $50,000.00 source → client_markup_total: 25500):
Response shape
The envelope is identical for previews and VA-bound quotes — onlyquote_id differs (null for previews).
Reading the response
- Amounts are integer minor units paired with
precision— not decimal strings.5000000withprecision: 2is$50,000.00;49920000000withprecision: 6is49,920.00 USDC. Format withamount / 10^precision; do not parse as a float. fees[]is itemized. Each line has acode, akind(fixed|percentage),charged_by(kira= Kira revenue;client= your markup), astatus(active|waived|deprecating), aversion, anddeprecated_at(nullunless the code is being phased out). Percentage lines additionally carrycalculation_method,rate_bps,basis_amount, andbasis_currency. Per-transaction markup overrides surface here asclient_markup_fixed/client_markup_percentage.totalsare disjoint.kira_revenue_totalandclient_markup_totalnever overlap;fee_total = kira_revenue_total + client_markup_total, andsource_net_amount = source.amount − fee_total.pricing_context.tieristier_1|tier_2|tier_3.month_cumulativeis your running month-to-date inbound volume (inmonth_cumulative_currencyminor units) that drives the tier; treat it as informational — it is0until the per-client TPV snapshot is enabled for your account.conversionexposes both the appliedrateand the underlyingmarket_rate, plus theclampandrate_source. Fees are always computed on the face-value 1:1 notional; the rate only affectsrecipient.amount.
balance_sufficient (top-level, held-balance quotes only) is an advisory boolean: true when your on-book balance for the source currency covered source.amount at quote time. It is absent on non-held quotes (and if the snapshot read fails). It is not a reservation — the authoritative check is the row-locked read at redemption — but it lets you surface early “insufficient funds” feedback.Returned fee codes
Everyfees[] line carries a code. The codes Kira may return — kira lines are Kira revenue, client lines are your markup, and the two never overlap:
Crypto-funded off-ramp: both inbound and conversion
A crypto-funded payout —payment_instructions set, from_held_balance absent — quotes an outbound delivery whose funding is a fresh crypto deposit. Because that deposit is a new receipt of external money, the quote prices the inbound receipt fee and the conversion_off_ramp spread on the stablecoin→fiat leg. Only from_held_balance: true suppresses the inbound leg — an on-book balance already paid it at its original receipt.
Request — deposit USDC on Solana, deliver USD by domestic wire:
fees[] array carries both Kira percentage legs (amounts illustrative, at Tier I rates).
A USD-pegged stablecoin source is priced on its USD face value (1:1), so source, fees[] and
totals are all denominated in USD — the $300,000.00 deposit is source.amount: 30000000 at
precision: 2, and conversion.pair ("USDC/USD") is what names the stablecoin you deposit:
inbound is $240.00 (8 bps) and conversion_off_ramp is $180.00 (6 bps) — the percentage legs
bill on the USD notional at the same rate_bps they would on a USD-funded quote of the same size.
The funding deposit’s network pass-through appears as a <network>_<direction> fixed line (here solana_inbound, $0 at this tier) — a $0 leg is still itemized, so include it in your reconciliation rather than assuming it is absent.
On the on-ramp direction — a fiat deposit converted to stablecoin — the conversion leg is
conversion_on_ramp instead; the inbound leg is identical. Fixed rail/network lines carry their own currency, which can differ from the percentage legs’ currency (here USDC legs alongside a USD wire line).C. Redeem the quote in a payout
Pass thequote_id from a VA-bound quote to the payout. The fees are locked from the quote — settlement does not re-price.
- A quote redeems once. Re-using a redeemed
quote_idfor a different payout returns400. - An expired or cancelled quote returns
400. - The quote must match the payout: redeeming a quote whose
targetcurrency/network differs from the recipient returns400(Recipient currency … does not match quote currency …), and a payout drawn from the held balance requires a quote issued withfrom_held_balance: true(… requires a quote issued with from_held_balance: true). Re-quote with the correct flags if you hit either. - If the payout fails before the transfer is created, the quote is released back to redeemable.
quote_idis optional on a payout — omit it and settlement prices the fees fresh at execution time (without the 15-minute lock).
amount on the payout body is a two-decimal string ("50000.00"), not a number. The full payout request shape — including the recipient and mode — is documented under Payouts in the API reference. OTP does not apply to API-key integrators — see Known limitations → Payouts.Migrating from payout/preview + create_quote
The previous pricing model used POST /v1/virtual-accounts/{id}/payout/preview (optionally with create_quote: true to lock a quote). The itemized endpoint replaces it for new integrations. Both flows share the same lock window (GENERAL_QUOTATION_LIFESPAN_MINUTES, default 15 minutes) — what changes is the fee shape, not the TTL.
1
Pin the version
Add
X-Api-Version: 2026-06-01 to your quotation calls.2
Switch amount parsing
Read integer minor units +
precision (stop parsing decimal strings as floats).3
Iterate fees[]
Replace bucket reads with iterating
fees[]; filter on charged_by to separate Kira’s fees from your markup.4
Quote once, redeem once
Store the returned
quote_id and pass it to the payout — instead of re-pricing at each step.5
Handle expiry
A quote is valid for 15 minutes (
quote_expires_at); re-quote if it lapses.6
Enable the engine
Ask your account manager to enable the new pricing engine for your account when you are ready to see itemized fees from it.
Errors
Errors carry a machine-readablecode plus a human message; switch on code.
Next steps
API reference
The full request/response schema for
POST /v1/quotations and the payout endpoints.Versioning
How to pin
X-Api-Version and upgrade your account default.Authentication
The token lifecycle and the
x-api-key + bearer credentials every call needs.Quickstart
The end-to-end sandbox flow: user, virtual account, deposit, payout.