Virtual Accounts

Overview

Virtual Accounts are U.S. bank accounts (US_BANK) that receive USD deposits via ACH or wire transfer. They operate in two modes:

ModeHow it worksDestination required
CryptoDeposits are automatically converted to stablecoins (USDC/USDT) and sent to a blockchain walletYes
FiatDeposits are held as a USD balanceNo

The mode is determined at creation time based on whether a destination wallet is provided. Once created, the mode cannot be changed.

Both modes support payouts - sending USD to any bank account via WIRE or SWIFT. See the Payouts Guide for details.

How It Works

Crypto Mode

  1. Create virtual account with a destination wallet
  2. Share the bank details with payers
  3. Payer sends USD via ACH or wire
  4. Funds are automatically converted to stablecoins and sent to the destination wallet
  5. You receive a webhook notification when the settlement is complete

Fiat Mode

  1. Create virtual account without a destination
  2. Share the bank details with payers
  3. Payer sends USD via ACH or wire
  4. Funds are added to the VA's USD balance
  5. You receive a webhook notification when the deposit arrives

Supported Configurations

CurrencyNetwork
USDCSolana
USDCPolygon
USDTPolygon

Bank Providers

BankCrypto ModeFiat ModeNotes
portageYesYesFor non-US based users
austin_capital_trustYesYesFor US-based users
slovak_savings_bankYesYesSandbox only

Deprecated: lead_bank is no longer supported. Existing accounts remain functional, but new accounts cannot be created with this bank.

Sandbox: Only slovak_savings_bank is available in the sandbox environment.

Production: Use portage for non-US based users and austin_capital_trust for US-based users.

Prerequisites

Before creating virtual accounts, ensure:

  • You're authenticated (Getting Started)
  • User has been created (User Management)
  • User is verified (Verification)
  • For Crypto Mode: User has a blockchain wallet (Solana, Polygon, or Tron)
  • For Fiat Mode: No wallet required

Use Cases

US_BANK (USD Virtual Accounts)

  • Freelancers receiving payments from U.S. clients
  • Contractors getting paid for project work
  • SMBs accepting payments from U.S. customers
  • Remote workers receiving salary in crypto

Fiat Mode (USD Holding)

  • Treasury management - hold USD without immediate conversion
  • Payment aggregation - collect multiple payments before converting
  • Timing flexibility - convert to crypto when rates are favorable
  • Fiat-only workflows - maintain USD balance for fiat operations

Guides in This Section

1. Virtual Accounts

Virtual Accounts Guide

Learn how to:

  • Create US_BANK virtual accounts
  • Select the appropriate bank provider
  • Get deposit instructions (bank details)
  • Manage account status and lifecycle
  • Support multiple blockchains and currencies

Key endpoints:

  • POST /v1/virtual-accounts - Create virtual account
  • GET /v1/virtual-accounts/{id} - Get virtual account details
  • GET /v1/virtual-accounts/{id}/balance - Get account balance (fiat mode)
  • POST /v1/virtual-accounts/{id}/payout - Initiate payout (fiat mode)

2. Deposits

Deposits Guide

Learn how to:

  • Track incoming deposits
  • View deposit history
  • Get blockchain transaction hashes
  • Calculate total received

Key endpoint:

  • GET /v1/virtual-accounts/{id}/deposits - Get deposits

3. Payouts (Fiat Mode)

Payouts Guide

Learn how to:

  • Preview fees before initiating a payout
  • Send funds from US_BANK fiat mode accounts via WIRE or SWIFT
  • Create and use WIRE/SWIFT recipients
  • Understand fee structure (base fees, client markup)
  • Track payout status and lifecycle
  • Handle payout webhooks

Key endpoints:

  • POST /v1/virtual-accounts/{id}/payout/preview - Preview fees before payout
  • POST /v1/virtual-accounts/{id}/payout - Send funds to a WIRE/SWIFT recipient

4. Liquidation Address (Crypto to USD)

Liquidation Address Guide

Learn how to:

  • Create a crypto wallet that automatically converts to USD
  • Configure ACH, WIRE, or SWIFT recipients for payouts
  • Handle liquidation webhooks
  • Track crypto deposits and USD payouts

Key endpoints:

  • POST /v1/virtual-accounts/{id}/liquidation-address - Create liquidation address
  • GET /v1/virtual-accounts/{id}/liquidation-address - List all liquidation addresses
  • GET /v1/virtual-accounts/{id}/liquidation-address/{addressId} - Get liquidation address by ID

Quick Start

1. Create US_BANK Virtual Account

curl -X POST https://api.balampay.com/v1/virtual-accounts \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: $(uuidgen)" \
  -d '{
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "US_BANK",
    "bank": "portage",
    "destination": {
      "currency": "USDC",
      "network": "solana",
      "address": "7tQJvFk8XZoaVRjL..."
    }
  }'

2. Create Fiat Mode Account (No Crypto Conversion)

curl -X POST https://api.balampay.com/v1/virtual-accounts \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: $(uuidgen)" \
  -d '{
    "user_id": "550e8400-e29b-41d4-a716-446655440000",
    "type": "US_BANK",
    "bank": "portage"
  }'

Note: Fiat mode is only available for portage and slovak_savings_bank. Omitting the destination field creates a fiat mode account.

3. Response with Deposit Instructions

US_BANK Response (Crypto Mode):

{
  "id": "va_789012345",
  "status": "activating",
  "type": "US_BANK",
  "bank": "portage",
  "source_deposit_instructions": null,
  "destination": {
    "currency": "USDC",
    "network": "solana",
    "address": "7tQJvFk8XZoaVRjL..."
  },
  "created_at": "2024-01-15T10:30:00Z"
}

US_BANK Response (Fiat Mode):

{
  "id": "va_789012347",
  "status": "activating",
  "type": "US_BANK",
  "bank": "portage",
  "source_deposit_instructions": null,
  "destination": null,
  "created_at": "2024-01-15T10:30:00Z"
}

Note: Fiat mode accounts have destination: null. Funds are held in USD and can be disbursed via POST /v1/virtual-accounts/{id}/payout.

Bank Selection (US_BANK)

For US_BANK accounts, you must specify which bank to use:

BankDescriptionFiat ModeUse For
portagePortage BankYesNon-US based users
austin_capital_trustAustin Capital TrustYesUS-based users
slovak_savings_bankSlovak Savings BankYesSandbox only

Deprecated: lead_bank is no longer supported. Existing accounts remain functional, but new accounts cannot be created with this bank.

Sandbox: Only slovak_savings_bank is available in the sandbox environment.

Production: Use portage for non-US based users and austin_capital_trust for US-based users.

Supported Configurations

CurrencyNetwork
USDCSolana
USDCPolygon
USDTSolana
USDTPolygon
USDTTron

Virtual Account Status

StatusDescription
pendingAccount creation initiated
activatingAccount is being provisioned (async)
activeAccount is ready to receive deposits
failedAccount creation failed
deactivatedAccount has been closed

Payment Rails

ACH Transfer (US_BANK)

  • Speed: 1-3 business days
  • Cost: Low/free for sender
  • Limits: Typically $25K - $1M per transaction

Wire Transfer (US_BANK)

  • Speed: Same day or next day
  • Cost: $15-$50 for sender
  • Types: Domestic and international

Fiat Mode Operations

For virtual accounts in fiat mode (no destination), use these endpoints to manage funds:

Get Balance

curl -X GET https://api.balampay.com/v1/virtual-accounts/va_789012347/balance \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-api-key: $API_KEY"

Response:

{
  "virtual_account_id": "va_789012347",
  "available_balance": "5000.00",
  "currency": "USD"
}

Initiate Payout

Note: Payouts are only available for US_BANK fiat mode accounts. You must first create a WIRE or SWIFT recipient.

curl -X POST https://api.balampay.com/v1/virtual-accounts/va_789012347/payout \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-api-key: $API_KEY" \
  -H "Content-Type: application/json" \
  -H "idempotency-key: $(uuidgen)" \
  -d '{
    "amount": "1000.00",
    "recipient_id": "550e8400-e29b-41d4-a716-446655440020"
  }'

Response:

{
  "id": "po_123456789",
  "virtual_account_id": "va_789012347",
  "recipient_id": "550e8400-e29b-41d4-a716-446655440020",
  "amount": "1000.00",
  "currency": "USD",
  "status": "pending",
  "fees": {
    "base_fees": {
      "fixed_fee": 15,
      "percentage_fee": 0.5,
      "fx_markup": 0
    },
    "client_markup": {
      "fixed_fee": 5,
      "percentage_fee": 0,
      "fx_markup": 0
    },
    "total_fees": 25
  },
  "recipient_amount": "975.00",
  "recipient_currency": "USD",
  "created_at": "2024-01-15T14:30:00Z"
}

Tip: Use POST /v1/virtual-accounts/{id}/payout/preview first to see fees before confirming.

See the Payouts Guide for detailed documentation.

Webhooks

Receive real-time notifications for virtual account events:

Virtual Account Created:

{
  "event": "virtual_account.created",
  "data": {
    "event_id": "uuid",
    "virtual_account_id": "va_123",
    "status": "active"
  }
}

Deposit Received:

{
  "event": "virtual_account.deposit_funds_received",
  "data": {
    "virtual_account_id": "va_123",
    "amount": "1000.00",
    "currency": "usdc",
    "source": {
      "payment_rail": "ach_push",
      "sender_name": "Acme Corporation"
    },
    "created_at": "2024-01-15T14:30:00Z"
  }
}

See the Webhooks Guide for setup instructions.

Complete Flow Diagram

sequenceDiagram
    participant User
    participant Your App
    participant Kira API
    participant Blockchain

    Note over Your App: Prerequisites: User created & verified

    Your App->>Kira API: POST /v1/virtual-accounts
    Kira API-->>Your App: Virtual Account + Deposit Instructions

    Your App->>User: Share Bank Details

    Note over User,Kira API: User sends payment

    User->>Kira API: USD Transfer

    Note over Kira API: Convert to USDC/USDT

    Kira API->>Blockchain: Send crypto to Wallet
    Blockchain-->>Kira API: Transaction Confirmed

    Kira API->>Your App: Webhook: Deposit Notification

    Your App->>Kira API: GET /v1/virtual-accounts/{id}/deposits
    Kira API-->>Your App: Deposit History

Legacy API (Deprecated)

Deprecation Notice: The endpoint POST /v1/users/{userId}/virtual-accounts is deprecated and will be removed in a future release. Please migrate to POST /v1/virtual-accounts.

Migration Guide

Legacy (Deprecated):

POST /v1/users/{userId}/virtual-accounts
{
  "type": "US_ACH",
  "destination": {...}
}

Current:

POST /v1/virtual-accounts
{
  "user_id": "{userId}",
  "type": "US_BANK",
  "bank": "portage",
  "destination": {...}
}

Key Changes:

  1. Endpoint changed from /v1/users/{userId}/virtual-accounts to /v1/virtual-accounts
  2. user_id is now in the request body, not the URL
  3. Type changed from US_ACH to US_BANK
  4. New required bank field for US_BANK accounts
  5. New status values: pending, failed

For legacy API documentation, see Legacy Virtual Accounts.


Related Documentation