Deposits
Overview
Once a virtual account is created and active, it can receive USD deposits via ACH or wire transfer. The Kira API provides endpoints to track deposits and their conversion to cryptocurrency.
Get Deposits
Endpoint
GET /virtual-accounts/{virtualAccountId}/deposits
Query Parameters
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
limit | integer | No | 10 | Number of deposits to return (1-100) |
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer token from authentication |
x-api-key | Yes | Your API key |
Example Request
curl -X GET "https://api.balampay.com/virtual-accounts/va_789012345/deposits?limit=20" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-H "x-api-key: YOUR_API_KEY"Response
[
{
"id": "dep_abc123",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"virtual_account_id": "va_789012345",
"type": "payment_processed",
"amount": "1000.00",
"currency": "usdc",
"created_at": "2024-01-15T14:30:00Z",
"source": {
"description": "ACH Push",
"payment_rail": "ach_push",
"sender_routing_number": "021000021",
"sender_name": "Acme Corporation"
},
"destination_tx_hash": "5KYmFMZ3qvX7h8sN9Qr1pL2wJ3vT4uB6nK7xM8yE9rF1gH2jD3kL4m"
},
{
"id": "dep_def456",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"virtual_account_id": "va_789012345",
"type": "payment_processed",
"amount": "500.00",
"currency": "usdc",
"created_at": "2024-01-14T09:15:00Z",
"source": {
"description": "Wire",
"payment_rail": "wire",
"sender_name": "John Smith"
},
"destination_tx_hash": "2JxK9qL5mN3oP7rS1tU4vW6xY8zA1bC2dE3fG4hI5jK6lM7nO8pQ9r"
}
]Response Fields
| Field | Type | Description |
|---|---|---|
id | string | Unique deposit event ID |
user_id | string | User who owns the virtual account |
virtual_account_id | string | Virtual account that received the deposit |
type | string | Event type - always payment_processed for deposits |
amount | string | Amount of cryptocurrency sent to wallet |
currency | string | Cryptocurrency type (usdc) |
created_at | string | ISO 8601 timestamp of when funds were received |
source | object | Information about the sender |
source.description | string | Payment method description |
source.payment_rail | string | How funds were sent: ach_push or wire |
source.sender_routing_number | string | Sender's bank routing number (if available) |
source.sender_name | string | Name of the sender |
destination_tx_hash | string | Blockchain transaction hash |
Deposit Lifecycle
1. Funds Received
USD arrives at the virtual account via ACH or wire transfer.
Event Type: funds_received
Status: Funds are pending conversion
2. Payment Submitted
Cryptocurrency transaction has been submitted to the blockchain.
Event Type: payment_submitted
Status: Transaction pending blockchain confirmation
3. Payment Processed
Cryptocurrency has been confirmed and settled in the destination wallet.
Event Type: payment_processed ✅
Status: Complete - funds are available in wallet
4. Additional States
In Review:
- Event Type:
in_review - Status: Transaction is under manual review for compliance
- Action: Wait for review to complete
Refunded:
- Event Type:
refunded - Status: Deposit was refunded to sender
- Reason: Usually due to compliance issues or insufficient information
Payment Rails
ACH Push (ach_push)
Standard bank transfer from a U.S. bank account.
Characteristics:
- Speed: 1-3 business days
- Cost: Low or free for sender
- Limits: Typically $25,000 - $1,000,000 per transaction
- Reversible: Can be reversed within 60 days
Example:
{
"source": {
"description": "ACH Push",
"payment_rail": "ach_push",
"sender_routing_number": "021000021",
"sender_name": "Acme Corporation"
}
}Wire Transfer (wire)
Direct bank-to-bank transfer.
Characteristics:
- Speed: Same day to next day
- Cost: $15-$50 for sender
- Limits: Typically unlimited
- Reversible: Generally not reversible
Example:
{
"source": {
"description": "Wire",
"payment_rail": "wire",
"sender_name": "International Corp"
}
}Tracking Deposits on Blockchain
Use the destination_tx_hash to view the transaction on the blockchain explorer:
Solana
https://solscan.io/tx/{destination_tx_hash}
Polygon
https://polygonscan.com/tx/{destination_tx_hash}
Deposit Amounts and Fees
The amount field shows the final cryptocurrency amount sent to the wallet, after any fees.
Example with fees:
Original USD received: $1,000.00
Platform fee (2%): $20.00
Net USD amount: $980.00
Conversion rate: 1 USD = 1 USDC
Final USDC sent: 980.00 USDC
The deposit response shows:
{
"amount": "980.00",
"currency": "usdc"
}Webhooks for Deposits
Instead of polling the deposits endpoint, set up webhooks to receive real-time notifications. See the Webhooks guide.
Deposit Webhook Payload
{
"event": "virtual_account.deposit_funds_received",
"data": {
"virtual_account_id": "va_789012345",
"amount": "1000.00",
"currency": "usdc",
"source": {
"payment_rail": "ach_push",
"sender_name": "Acme Corporation",
"sender_bank_routing_number": "021000021",
"trace_number": "123456789",
"description": "Payment from sender"
},
"destination_tx_hash": "5KYmFMZ3qvX7h8sN...",
"created_at": "2024-01-15T14:30:00Z"
}
}Common Scenarios
Scenario 1: Track All Deposits for a User
// Get all virtual accounts for user
const accounts = await fetch(
`https://api.balampay.com/v1/users/${userId}/virtual-accounts`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
).then(r => r.json());
// Get deposits for each account
for (const account of accounts) {
const deposits = await fetch(
`https://api.balampay.com/virtual-accounts/${account.id}/deposits?limit=100`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
).then(r => r.json());
console.log(`Account ${account.id}: ${deposits.length} deposits`);
}Scenario 2: Calculate Total Received
const deposits = await fetch(
`https://api.balampay.com/virtual-accounts/va_789012345/deposits?limit=100`,
{
headers: { 'Authorization': `Bearer ${token}` }
}
).then(r => r.json());
const total = deposits.reduce((sum, deposit) => {
return sum + parseFloat(deposit.amount);
}, 0);
console.log(`Total USDC received: ${total.toFixed(2)}`);Scenario 3: Display Deposit History to User
function formatDeposit(deposit) {
return {
date: new Date(deposit.created_at).toLocaleDateString(),
amount: `${deposit.amount} ${deposit.currency.toUpperCase()}`,
sender: deposit.source.sender_name,
method: deposit.source.payment_rail === 'ach_push' ? 'ACH' : 'Wire',
status: 'Completed',
transactionUrl: `https://solscan.io/tx/${deposit.destination_tx_hash}`
};
}
const formattedDeposits = deposits.map(formatDeposit);Testing Deposits in Sandbox
In sandbox mode, deposits must be tested using the actual banking details provided by the API. There is no endpoint to simulate deposits programmatically.
Error Responses
Invalid Virtual Account ID Format
Status: 400 Bad Request
{
"error": "Invalid request data",
"details": [
{
"path": "virtualAccountId",
"message": "Invalid virtual account ID format",
"code": "invalid_string"
}
]
}Virtual Account Not Found
Status: 404 Not Found
{
"code": "not_found",
"message": "Virtual account with ID va_789012345 not found or does not belong to client"
}Invalid Limit Parameter
Status: 400 Bad Request
{
"code": "validation_error",
"message": "Limit must be a number between 1 and 100"
}Unauthorized Access
Status: 401 Unauthorized
{
"code": "unauthorized",
"message": "No client ID found in claims"
}Internal Server Error
Status: 500 Internal Server Error
{
"code": "internal_error",
"message": "An unexpected error occurred"
}Best Practices
- Use webhooks for real-time updates - Don't poll the API frequently
- Store deposit IDs - Keep track of processed deposits to avoid duplicates
- Verify blockchain transactions - Cross-check with blockchain explorers
- Display sender information - Help users identify who sent the payment
- Show transaction hashes - Provide links to blockchain explorers
- Handle pagination - Use the limit parameter for accounts with many deposits
- Reconcile amounts - Account for fees when showing amounts to users
Troubleshooting
Deposit not showing up
Possible causes:
- ACH transfer still pending (takes 1-3 business days)
- Wire transfer being processed (check with sender's bank)
- Compliance review in progress
- Sender used incorrect bank details
Solutions:
- Check if sender has proof of transfer
- Verify sender used correct account/routing numbers
- Contact support with transfer reference number
Wrong amount received
Possible causes:
- Platform fees deducted
- Sender's bank charged fees
- Exchange rate fluctuation during conversion
Solutions:
- Check fee configuration in your client settings
- Review the webhook payload for fee breakdown
- Verify conversion rate at time of deposit
Transaction hash not working
Possible causes:
- Transaction still pending on blockchain
- Wrong blockchain explorer URL
- Network congestion causing delays
Solutions:
- Wait a few minutes and try again
- Verify using correct explorer for the blockchain
- Check blockchain status pages for network issues
Next Steps
- Set up webhooks for real-time deposit notifications
- Handle errors gracefully in your integration
- Build user-facing deposit history views
- Implement reconciliation and reporting
Updated 12 days ago
