Skip to main content
This walkthrough takes you end to end in the sandbox: authenticate, pin your version, create a user and a virtual account, and make a payout. Every example uses the sandbox base URL https://api.balampay.com/sandbox.
Sandbox seed IDs are tenant-scoped placeholders. The sandbox does not ship working shared seed IDs — values like verified_user_id, virtual_account_id, and recipient_id are placeholders, not live resources. Sandbox tenancy isolates these resources per client, so any baked-in UUID would return 404 for an integrator using their own api_key.You can create and verify a user (the sandbox triggers verification automatically for a complete user, but approval is a manual step — per Kira it can take up to 24 hours, not seconds), create recipients, and create a virtual account — all self-serve. A new sandbox VA activates automatically within about a minute (see Known limitations). Cross-tenant shared seeds are coming, but are not available yet.
1

Get your credentials

Kira provides three credentials for your tenant:
  • api_key — sent as the x-api-key header on every request, including /auth.
  • client_id and password — exchanged at POST /auth for a short-lived access token.
Keep them out of source control. The examples below read them from environment variables:
2

Authenticate

Call POST /auth with your client_id and password in the body and your x-api-key header. The /auth endpoint itself needs only x-api-key — no bearer token yet.
The response wraps the token in the success envelope:
Use the returned access_token as your bearer token on every other request. It is valid for 3600 seconds, so refresh it before it expires.
See Authentication for the full token lifecycle.
3

Pin your version

Send the X-Api-Version: 2026-04-14 header on every request. The header always selects the documented schema, always wins over your account’s stored default, and works no matter which version your account is pinned to — every example below includes it.Optionally, if your account’s current default is 2026-04-14 or older, you can also pin your account once with POST /v1/versioning/upgrade, after which the header becomes optional. Re-pinning to the same version is a safe no-op. See Versioning for details.
Pinning is forward-only. POST /v1/versioning/upgrade only moves your account pin to the same or a newer version. If your account is already pinned to a version newer than 2026-04-14, this call returns 400 "Cannot downgrade API version from '<current>' to '2026-04-14'. Upgrades are forward-only. To use an older documented version per-request, send the X-Api-Version header — it is exempt from this rule." — there is no self-serve downgrade. To integrate against 2026-04-14 regardless of your account pin, keep sending the per-request X-Api-Version: 2026-04-14 header: it always wins over the account default and is not subject to the forward-only rule.
4

Create a user

Create a user with POST /v1/users. A user is either an individual or a business. source_of_funds is optional at create — the call returns 201 without it — but it is a KYC questionnaire field that business (KYB) products require, so omitting it doesn’t reject the user outright; it leaves verification unable to proceed until you supply it. Send it on create to keep the flow moving.
This minimal body returns 201 as-is. To take the user all the way to VERIFIED, send the complete field set for its category (documents, address, questionnaire) — see Creating users for full example payloads.
The sandbox triggers verification automatically — but approval is manual, not instant. Verification triggers on its own once the payload is complete for a product (all required fields and documents — the missing_fields map on the response lists what is still outstanding). Per Kira, final approval can take up to 24 hours; a user can land in manual review (status: REVIEW) at any point in that window — more likely for businesses (KYB) and for low-quality or placeholder document images — which a Kira operator resolves. (Don’t build against a “verifies in seconds” assumption.) An incomplete user is not rejected — it stays CREATED with verification_triggered: false until you supply the missing fields with PUT /v1/users/{id}. A terminal REJECTED means the provider actually declined the submitted data; the reasons arrive only in the user.verification.failed webhook. Gate your state machine on status, not verification_status.
5

Create a virtual account

Create a virtual account for the user with POST /v1/virtual-accounts.
bank: "slovak_savings_bank" selects the recommended default rail. The bank value is environment-scoped: in production the same rail is bank: "portage" (sending portage in sandbox returns 400 "Invalid bank").
A VA being approved does not mean funds are ready: confirm readiness via account_number being a real value (it stays null while provisioning; on the ACT rail — bank: "austin_capital_trust" — it shows the "PENDING-ACT-ACCOUNT" placeholder instead, and ACT allows one VA per user: re-creating returns 409 Conflict). A new sandbox VA activates automatically — the sandbox polls provider status every 15 seconds, so expect activation (and the virtual_account.activated webhook) within about a minute (see Known limitations).
6

Make a payout

In the sandbox there’s no deposit to run first — an active VA reports a fixed provider available_balance (check it with GET /v1/virtual-accounts/{id}/balance).Payouts are a two-step flow: price it, then create it.Price with POST /v1/quotations. Pin X-Api-Version: 2026-06-01 on this call to get the itemized breakdown — one object per fee, plus the conversion rate and tier context. The quote is redeemable for 15 minutes.
rail is the bank rail you intend to pay out on (ACH_STANDARD, ACH_SAME_DAY, WIRE_DOMESTIC) — declare it so the quote prices that rail’s fixed fee. Paying from the VA’s on-book balance instead of a fresh deposit? Add "from_held_balance": true. Funding the payout with stablecoin? Send payment_instructions instead. Both, and the full response shape, are in Itemized quotations.
payout/preview is deprecated as of July 16, 2026 and is not shown here. It still works for existing integrations — see Payouts, quotations, and recipients — but do not build new integrations on it.
There is no fee schedule endpoint and no dry_run mode. For amounts below the minimum, POST /v1/quotations returns 400 with code: "fees_exceed_amount" and the message "The fees exceed the provided amount. Please increase the amount.", plus a details object (amount, total_fees) you can use to size the next attempt. The 201 create response returns lowercase status: "created", while GET /v1/payouts/{id} returns CREATED for the same payout — compare statuses case-insensitively.

Next steps

Authentication

The full token lifecycle, required headers, and credential handling.

Webhooks

Register an endpoint and consume deposit, user, and payout events.

API reference

Browse every endpoint, request shape, and response in the interactive reference.