Virtual Accounts
Overview
Virtual accounts are U.S. bank accounts that automatically convert incoming USD deposits into cryptocurrency and settle the funds to a designated blockchain wallet. Each virtual account has unique bank account details (account number and routing number) that can be used to receive ACH and wire transfers.
Prerequisites
Before creating a virtual account, ensure:
- ✅ User has been created
- ✅ User has completed identity verification (KYC/KYB)
- ✅ Verification status is
verified - ✅ User has a blockchain wallet created (Solana or Polygon)
Create Virtual Account
Endpoint
POST /v1/users/{userId}/virtual-accounts
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token from authentication |
x-api-key | Yes | Your API key |
Content-Type | Yes | Must be application/json |
idempotency-key | Yes | Unique identifier to prevent duplicate creation |
Request Body
{
"type": "US_ACH",
"destination": {
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjL..."
},
"description": "Primary deposit account",
"metadata": {
"customer_reference": "CUST-12345",
"account_purpose": "freelancer_payments"
}
}Field Descriptions
| Field | Type | Required | Description |
|---|---|---|---|
type | string | Yes | Account type: US_ACH (only US_ACH is currently supported) |
destination | object | Yes | Where to send converted cryptocurrency |
destination.currency | string | Yes | Cryptocurrency: USDC |
destination.network | string | Yes | Blockchain: solana or polygon |
destination.address | string | Yes | Wallet address on the specified blockchain |
description | string | No | Human-readable description of the account |
metadata | object | No | Custom key-value pairs for your reference |
Supported Configurations
| Currency | Network | Status |
|---|---|---|
| USDC | Solana | ✅ Supported |
| USDC | Polygon | ✅ Supported |
Example Request
curl -X POST https://api.balampay.com/v1/users/550e8400-e29b-41d4-a716-446655440000/virtual-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "idempotency-key: va-creation-$(date +%s)" \
-d '{
"type": "US_ACH",
"destination": {
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjLGcBdqN3hJq8VqBvGpPQy8R9xYwZ1"
},
"description": "Main receiving account for freelance payments"
}'Response
{
"id": "va_789012345",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "US_ACH",
"status": "active",
"destination": {
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjLGcBdqN3hJq8VqBvGpPQy8R9xYwZ1"
},
"source_deposit_instructions": {
"currency": "usd",
"bank_name": "Example Bank",
"bank_address": "123 Main Street, San Francisco, CA 94105",
"bank_account_number": "1234567890",
"bank_routing_number": "021000021",
"bank_beneficiary_name": "John Doe",
"bank_beneficiary_address": "456 Oak Ave, San Francisco, CA 94102"
},
"description": "Main receiving account for freelance payments",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}Virtual Account Status
| Status | Description | Actions Available |
|---|---|---|
activating | Account is being created | Wait - usually takes 1-2 minutes |
active | Account is ready to receive deposits | Can receive ACH/wire transfers |
deactivated | Account has been closed | Cannot receive deposits |
Bank Account Details
The source_deposit_instructions contain the bank account details that users need to receive USD payments:
Bank Name: [Provided by API]
Bank Address: [Provided by API]
Account Number: [Provided by API]
Routing Number: [Provided by API]
Beneficiary Name: [User's name]
Beneficiary Address: [User's address]
Using These Details
For ACH transfers:
- Domestic transfers from any U.S. bank
- Typically arrive within 1-3 business days
- Low or no fees for the sender
For Wire transfers:
- Same-day or next-day transfers
- Can be domestic or international
- Higher fees (typically $15-$50)
Get Virtual Accounts
Endpoint
GET /v1/users/{userId}/virtual-accounts
Example Request
curl -X GET https://api.balampay.com/v1/users/550e8400-e29b-41d4-a716-446655440000/virtual-accounts \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "x-api-key: YOUR_API_KEY"Response
[
{
"id": "va_789012345",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"type": "US_ACH",
"status": "active",
"destination": {
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjLGcBdqN3hJq8VqBvGpPQy8R9xYwZ1"
},
"source_deposit_instructions": {
"currency": "usd",
"bank_name": "Example Bank",
"bank_account_number": "1234567890",
"bank_routing_number": "021000021",
"bank_beneficiary_name": "John Doe"
},
"description": "Main receiving account",
"created_at": "2024-01-15T10:30:00Z"
}
]How Deposits Work
Step-by-Step Flow
sequenceDiagram
participant Sender
participant Sender Bank
participant Kira
participant Blockchain
participant User Wallet
Note over Sender,User Wallet: ACH/Wire Transfer Flow
Sender->>Sender Bank: Initiate transfer to virtual account
Sender Bank->>Kira: Send USD (ACH/Wire)
Note over Kira: USD received
Note over Kira: Convert USD to USDC
Kira->>Blockchain: Send USDC to destination
Blockchain->>User Wallet: USDC credited
Kira->>Your Server: Webhook: Deposit notification
Timing
| Transfer Type | Arrival Time | Conversion Time | Total Time |
|---|---|---|---|
| ACH | 1-3 business days | Instant | 1-3 business days |
| Wire (Domestic) | Same day or next day | Instant | Same day - 1 business day |
| Wire (International) | 1-5 business days | Instant | 1-5 business days |
Deposit Processing
- Funds Received: USD arrives at the virtual account
- Conversion: Instantly converted to USDC at current market rate
- Blockchain Settlement: Cryptocurrency sent to destination wallet
- Confirmation: Transaction confirmed on blockchain (seconds to minutes)
- Notification: Webhook sent to your server with deposit details
Fees
Kira may collect fees on deposits based on your client configuration. Fees are:
- Deducted from the deposit amount before conversion
- Configurable per client
- Visible in deposit webhooks and API responses
Example with fees:
USD Received: $1,000.00
Fee (2%): $20.00
Net Amount: $980.00
USDC Sent: ~980 USDC (after conversion)
Multiple Virtual Accounts
Users can create multiple virtual accounts for different purposes:
// Account 1: For freelance payments
const account1 = await createVirtualAccount({
destination: {
currency: 'USDC',
network: 'solana',
address: 'wallet1...'
},
description: 'Freelance payments'
});
// Account 2: For business invoices
const account2 = await createVirtualAccount({
destination: {
currency: 'USDC',
network: 'polygon',
address: 'wallet2...'
},
description: 'Business invoices'
});Each account has unique bank details, allowing users to:
- Track payments from different sources
- Route funds to different wallets
- Use different blockchains for different purposes
Error Responses
Missing or Invalid Request Fields
Status: 400 Bad Request
{
"error": "Invalid request data",
"details": [
{
"path": "destination.currency",
"message": "Required",
"code": "invalid_type"
}
]
}Missing Idempotency Key
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Idempotency key is required"
}Idempotency Key Reused with Different Data
Status: 400 Bad Request
Note: This returns as a validation error (not 409) for virtual accounts.
{
"code": "validation_error",
"message": "Idempotency key has already been used with different request data"
}Unauthorized
Status: 401 Unauthorized
{
"code": "unauthorized",
"message": "No client ID found in claims"
}User Not Found
Status: 400 Bad Request
{
"code": "validation_error",
"message": "User with ID 550e8400-e29b-41d4-a716-446655440000 not found or does not belong to client"
}Customer Not Found
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Customer not found: 550e8400-e29b-41d4-a716-446655440000"
}Customer Not Active
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Customer is not active: 550e8400-e29b-41d4-a716-446655440000. Please activate the customer first."
}Only US_ACH Supported
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Only US_ACH type is supported at the moment"
}Invalid Wallet Address or Currency/Network Combination
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Invalid Solana wallet address format"
}Internal Server Error
Status: 500 Internal Server Error
{
"code": "internal_error",
"message": "An unexpected error occurred"
}Idempotency
Use the idempotency-key header to safely retry requests:
# First request - creates virtual account
curl -X POST https://api.balampay.com/v1/users/{userId}/virtual-accounts \
-H "idempotency-key: unique-key-123" \
-d '{...}'
# Second request with same key and body - returns existing account
curl -X POST https://api.balampay.com/v1/users/{userId}/virtual-accounts \
-H "idempotency-key: unique-key-123" \
-d '{...}'Best Practices
- Validate wallet addresses - Double-check wallet addresses before creating accounts
- Use descriptive names - Add meaningful descriptions to identify account purposes
- Store bank details securely - Save
source_deposit_instructionsfor display to users - Monitor via webhooks - Don't poll; use webhooks for real-time deposit notifications
- Test network connectivity - Verify wallet address can receive transactions before creating account
- Handle activating state - Wait for
activestatus before showing bank details to users - Communicate clearly - Explain to users how long transfers take and what fees apply
Displaying Bank Details to Users
When showing bank details to users, provide clear instructions:
To receive payments, share these details with the sender:
Bank Name: {bank_name}
Bank Address: {bank_address}
Account Information:
Account Number: {bank_account_number}
Routing Number: {bank_routing_number}
Beneficiary:
Name: {bank_beneficiary_name}
Address: {bank_beneficiary_address}
⏱️ ACH transfers: 1-3 business days
⏱️ Wire transfers: Same day or next day
💡 Once received, USD will be automatically converted to USDC
and sent to your wallet.
Next Steps
After creating a virtual account:
- Track deposits and monitor settlement
- Set up webhooks for real-time notifications
- Display bank details to your users
- Monitor account activity via the deposits API
Updated 12 days ago
