Virtual Account Webhooks
Overview
Webhooks provide real-time notifications for virtual account events. Configure a webhook endpoint to receive automatic updates when deposits arrive, payouts are processed, or account status changes.
Webhook Events
| Event | Description | VA Mode |
|---|---|---|
virtual_account.created | Virtual account created | All |
virtual_account.activated | Virtual account is now active | All |
virtual_account.deposit_funds_received | Deposit received at virtual account | All |
virtual_account.microdeposit_funds_received | Microdeposit received (< $1.00 USD) | All |
virtual_account.deposit_funds_in_transit | Deposit settlement started (crypto conversion in progress) | Crypto only |
virtual_account.deposit_funds_in_destination | Deposit settlement completed (crypto sent to wallet) | Crypto only |
virtual_account.deposit_funds_failed | Deposit settlement failed | Crypto only |
payout.created | Payout created | Both |
payout.deposit_received | Stablecoins received at deposit address | Crypto payout only |
payout.status_changed | Payout status transition (pending, processing) | Both |
payout.completed | Payout successfully sent to recipient | Both |
payout.failed | Payout failed | Both |
payout.returned | Funds returned after being sent | Both |
Virtual Account Events
virtual_account.created
Sent when a virtual account is created.
{
"event": "virtual_account.created",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440001",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"status": "activating"
}
}virtual_account.activated
Sent when a virtual account transitions to active status and is ready to receive deposits.
{
"event": "virtual_account.activated",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440003",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"status": "active"
}
}Deposit Events
virtual_account.deposit_funds_received
Sent when USD funds arrive at the virtual account via wire or ACH transfer. This is the primary deposit event for both crypto and fiat mode accounts.
The source field varies depending on the payment rail (wire vs ACH).
Wire Deposit
{
"event": "virtual_account.deposit_funds_received",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440010",
"deposit_id": "550e8400-e29b-41d4-a716-446655440011",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"amount": "1000.00",
"currency": "usd",
"status": "completed",
"source": {
"payment_rail": "wire",
"sender_name": "Acme Corporation",
"sender_account_number": "9876543210",
"sender_address": "123 Main St, New York, NY 10001",
"imad": "20240115MQFNP000001234",
"omad": "20240115MQFNP000005678",
"wire_message": "Invoice payment #1234"
},
"created_at": "2024-01-15T14:30:00Z"
}
}ACH Deposit
{
"event": "virtual_account.deposit_funds_received",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440012",
"deposit_id": "550e8400-e29b-41d4-a716-446655440013",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"amount": "500.00",
"currency": "usd",
"status": "completed",
"source": {
"payment_rail": "ach_push",
"sender_name": "John Smith",
"sender_account_number": "1234567890",
"trace_number": "123456789012345",
"sec_code": "CCD"
},
"created_at": "2024-01-15T09:15:00Z"
}
}Refunded Deposit
{
"event": "virtual_account.deposit_funds_received",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440014",
"deposit_id": "550e8400-e29b-41d4-a716-446655440015",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"amount": "200.00",
"currency": "usd",
"status": "refunded",
"source": {
"payment_rail": "wire",
"sender_name": "Unknown Sender"
},
"created_at": "2024-01-15T16:00:00Z"
}
}Source Fields
| Field | Wire | ACH | Description |
|---|---|---|---|
payment_rail | "wire" | "ach_push" | How funds were sent |
sender_name | Yes | Yes | Name of the sender |
sender_account_number | Optional | Optional | Sender's bank account number |
sender_address | Optional | No | Sender's address |
imad | Optional | No | Input Message Accountability Data |
omad | Optional | No | Output Message Accountability Data |
wire_message | Optional | No | Wire memo/message |
trace_number | No | Optional | ACH trace number |
sec_code | No | Optional | SEC code (CCD, PPD, WEB) |
Deposit Status
| Status | Description |
|---|---|
completed | Deposit received and processed |
refunded | Deposit was returned to sender |
Microdeposit Event
virtual_account.microdeposit_funds_received
Sent when a deposit under $1.00 USD is received. Microdeposits do not trigger crypto settlement - no deposit_funds_in_transit or deposit_funds_in_destination events are emitted.
{
"event": "virtual_account.microdeposit_funds_received",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440016",
"deposit_id": "550e8400-e29b-41d4-a716-446655440017",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"amount": "0.50",
"currency": "usd",
"status": "completed",
"source": {
"payment_rail": "ach_push",
"sender_name": "Verification Service",
"trace_number": "123456789012345"
},
"created_at": "2024-01-15T10:00:00Z"
}
}Note: Microdeposits are typically used for account verification purposes. The payload structure is the same as
deposit_funds_received.
Deposit Settlement Events (Crypto Mode Only)
For crypto mode virtual accounts, after a deposit is received, the system converts the funds to stablecoins and sends them to the configured destination wallet. These events track that settlement process.
Note: These events only apply to crypto mode VAs. Fiat mode deposits do not trigger settlement - the balance is simply updated.
virtual_account.deposit_funds_in_transit
Sent when the settlement process begins (internal transfer initiated, crypto conversion queued).
{
"event": "virtual_account.deposit_funds_in_transit",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440030",
"deposit_id": "550e8400-e29b-41d4-a716-446655440011",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "pending",
"source": {
"amount": "10000.00",
"currency": "USD"
},
"destination": {
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjL..."
},
"processing_started_at": "2024-01-15T14:31:00Z"
}
}virtual_account.deposit_funds_in_destination
Sent when stablecoins have been successfully sent to the destination wallet. Includes a full settlement breakdown showing fees deducted and FX conversion details.
{
"event": "virtual_account.deposit_funds_in_destination",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440031",
"deposit_id": "550e8400-e29b-41d4-a716-446655440011",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "completed",
"source": {
"amount": "10000.00",
"currency": "USD"
},
"destination": {
"amount": "9910.09",
"currency": "USDC",
"network": "solana",
"address": "7tQJvFk8XZoaVRjL...",
"tx_hash": "5KYmFMZ3qvX7h8sN..."
},
"settlement": {
"platform_fees": {
"base_fee": "15.00",
"percentage_fee": "12.00",
"total": "27.00"
},
"client_fees": {
"total": "51.00"
},
"total_fees": "78.00",
"fee_currency": "USD",
"fx": {
"commercial_rate": "1.0000",
"applied_rate": "0.9988",
"markup_rate": "0.0012",
"markup_cost": "11.91"
}
},
"completed_at": "2024-01-15T14:35:00Z"
}
}Settlement Fields
| Field | Description |
|---|---|
settlement.platform_fees.base_fee | Fixed fee charged by the platform (rail-specific) |
settlement.platform_fees.percentage_fee | Percentage-based fee on deposit amount |
settlement.platform_fees.total | Sum of platform base + percentage fees |
settlement.client_fees.total | Fee markup configured by the client |
settlement.total_fees | Total fees deducted from deposit (platform + client) |
settlement.fee_currency | Currency in which fees are denominated |
settlement.fx.commercial_rate | Raw market exchange rate |
settlement.fx.applied_rate | Rate after FX markup: commercial_rate × (1 - markup_rate) |
settlement.fx.markup_rate | FX markup rate applied to conversion |
settlement.fx.markup_cost | Dollar cost of the FX markup on net amount |
How destination amount is calculated:
destination.amount = (source.amount - total_fees) × applied_rateExample: (10,000.00 - 78.00) × 0.9988 = 9,910.09 USDC
virtual_account.deposit_funds_failed
Sent when the settlement process fails (e.g., crypto transfer failure).
{
"event": "virtual_account.deposit_funds_failed",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440032",
"deposit_id": "550e8400-e29b-41d4-a716-446655440011",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440002",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"status": "failed",
"source": {
"amount": "10000.00",
"currency": "USD"
},
"failure_reason": "Settlement transfer failed",
"failed_at": "2024-01-15T14:35:00Z"
}
}Payout Events
Payout events apply to both fiat and crypto mode payouts. The crypto mode includes additional events like payout.deposit_received.
payout.created
Sent when a payout is created.
Fiat mode - VA balance is debited, wire transfer queued:
{
"event": "payout.created",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440020",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440003",
"recipient_id": "550e8400-e29b-41d4-a716-446655440020",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"fees": {
"base_fees": {
"fixed_fee": "15.00",
"percentage_fee": "5.00"
},
"client_markup": {
"fixed_fee": "2.00",
"percentage_fee": "1.00"
},
"total_fees": "23.00"
},
"status": "created",
"created_at": "2024-01-15T14:30:00Z"
}
}Crypto mode - Deposit wallet generated, awaiting stablecoin deposit:
{
"event": "payout.created",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440021",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440001",
"recipient_id": "550e8400-e29b-41d4-a716-446655440020",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"fees": {
"base_fees": {
"fixed_fee": "15.00",
"percentage_fee": "5.00"
},
"client_markup": {
"fixed_fee": "2.00",
"percentage_fee": "1.00"
},
"total_fees": "23.00"
},
"status": "created",
"deposit_instructions": {
"network": "solana",
"currency": "USDC",
"address": "KiraXyz123...",
"expires_at": "2024-01-16T14:30:00Z"
},
"created_at": "2024-01-15T14:30:00Z"
}
}payout.deposit_received
Crypto mode only. Sent when stablecoins are detected at the deposit wallet address.
{
"event": "payout.deposit_received",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440022",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440001",
"deposit": {
"tx_hash": "5KYmFMZ3qvX7h8sN...",
"from_address": "SenderWallet...",
"amount": "1000.00",
"token": "USDC",
"network": "solana"
},
"status": "deposit_received",
"updated_at": "2024-01-15T14:35:00Z"
}
}payout.status_changed
Sent when a payout transitions between intermediate statuses (e.g., pending, processing).
{
"event": "payout.status_changed",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440026",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440003",
"status": "pending",
"previous_status": "created",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"updated_at": "2024-01-15T14:30:30Z"
}
}Note: The
statusfield can bePENDING(queued for execution) orPROCESSING(wire/SWIFT transfer being routed).
payout.completed
Sent when the wire/SWIFT transfer has been completed and funds delivered to the recipient.
{
"event": "payout.completed",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440023",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440003",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"status": "completed",
"updated_at": "2024-01-17T10:15:00Z"
}
}payout.failed
Sent when a payout fails at any stage of processing.
{
"event": "payout.failed",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440024",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440003",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"status": "failed",
"updated_at": "2024-01-15T14:35:00Z"
}
}payout.returned
Sent when funds are returned after being sent.
{
"event": "payout.returned",
"data": {
"event_id": "evt_550e8400-e29b-41d4-a716-446655440025",
"payout_id": "550e8400-e29b-41d4-a716-446655440010",
"virtual_account_id": "550e8400-e29b-41d4-a716-446655440003",
"amount": "1000.00",
"currency": "USD",
"recipient_amount": "977.00",
"recipient_currency": "USD",
"status": "returned",
"updated_at": "2024-01-20T09:00:00Z"
}
}Event Flow by Account Mode
Fiat Mode - Deposit + Payout
sequenceDiagram
participant Sender
participant Banking Partner
participant Kira
participant Your Server
participant Recipient Bank
Note over Sender,Your Server: Deposit Flow
Sender->>Banking Partner: Send USD (ACH/Wire)
Banking Partner->>Kira: Webhook: wire_inbound/ach_credit
Kira->>Your Server: virtual_account.deposit_funds_received
Note over Your Server,Recipient Bank: Payout Flow
Your Server->>Kira: POST /payout
Kira->>Your Server: payout.created
Kira->>Your Server: payout.status_changed (PENDING)
Kira->>Banking Partner: Wire outbound
Kira->>Your Server: payout.status_changed (PROCESSING)
Banking Partner->>Recipient Bank: WIRE/SWIFT
Banking Partner-->>Kira: Completed
Kira->>Your Server: payout.completed
Crypto Mode - Deposit + Settlement
sequenceDiagram
participant Sender
participant Banking Partner
participant Kira
participant Your Server
participant Blockchain
Sender->>Banking Partner: Send USD (ACH/Wire)
Banking Partner->>Kira: Webhook: wire_inbound/ach_credit
Kira->>Your Server: virtual_account.deposit_funds_received
Note over Kira: Crypto settlement
Kira->>Your Server: virtual_account.deposit_funds_in_transit
Kira->>Blockchain: Send stablecoins to destination
Blockchain-->>Kira: Transaction confirmed
Kira->>Your Server: virtual_account.deposit_funds_in_destination
Crypto Mode - Payout (Stablecoin Funded)
sequenceDiagram
participant Your Server
participant Kira
participant Blockchain
participant Banking Partner
participant Recipient Bank
Your Server->>Kira: POST /payout (with payment_instructions)
Kira->>Your Server: payout.created (with deposit_instructions)
Note over Your Server,Blockchain: Send stablecoins
Your Server->>Blockchain: Transfer stablecoins
Blockchain-->>Kira: Deposit detected
Kira->>Your Server: payout.deposit_received
Kira->>Your Server: payout.status_changed (PENDING)
Kira->>Banking Partner: Wire outbound
Kira->>Your Server: payout.status_changed (PROCESSING)
Banking Partner->>Recipient Bank: WIRE/SWIFT
Banking Partner-->>Kira: Completed
Kira->>Your Server: payout.completed
Best Practices
- Always return 200 - Acknowledge receipt immediately, process asynchronously
- Handle duplicates - Use
event_idorpayout_idto detect duplicate deliveries - Process idempotently - Ensure handling the same event twice doesn't cause issues
- Log all events - Keep records for debugging and reconciliation
- Set up monitoring - Alert on failed webhook deliveries or processing errors
- Handle all event types - Even if you only care about some, log unknown types
- Verify webhook signatures - See Webhooks Guide for signature verification
Related Documentation
- Virtual Accounts Guide - Create and manage virtual accounts
- Deposits Guide - Track incoming deposits
- Payouts Guide - Initiate payouts (fiat and crypto modes)
- Webhooks Setup - Configure webhook endpoints and signature verification
Updated about 2 months ago
