# Virtual cash webhook events

This guide documents the webhook event types available for the virtual cash domain. Webhooks enable you to track virtual cash increases and decreases through their complete lifecycle and be notified immediately at each state transition, eliminating the need to poll for status updates.

## Event types overview

Upvest sends webhook notifications whenever a virtual cash increase or decrease changes status during processing. The **VIRTUAL_CASH_INCREASE.*** and **VIRTUAL_CASH_DECREASE.*** events fire at each state transition as requests progress from initial creation through confirmation, queuing, or cancellation, allowing your application to track the entire lifecycle.

Virtual cash operations enable managing tradeable balances for your end users. Each operation progresses through defined states, with webhooks sent for each transition: ISSUED (request created) → CONFIRMED (balance available or removed) or QUEUED (pending sufficient funds) or CANCELLED.

## Virtual cash event table

| Event type | Trigger | Status | Description |
|  --- | --- | --- | --- |
| **VIRTUAL_CASH_INCREASE.ISSUED** | Increase requested. | Immediate | A virtual cash increase request has been created. The balance increase is pending confirmation. |
| **VIRTUAL_CASH_INCREASE.CONFIRMED** | Increase confirmed. | Immediate | The virtual cash increase has been confirmed. The balance is now available for trading. |
| **VIRTUAL_CASH_DECREASE.ISSUED** | Decrease requested. | Immediate | A virtual cash decrease request has been created. The balance reduction is pending confirmation. |
| **VIRTUAL_CASH_DECREASE.CONFIRMED** | Decrease confirmed. | Immediate | The virtual cash decrease has been confirmed. The cash balance has been removed from the account. |
| **VIRTUAL_CASH_DECREASE.QUEUED** | Insufficient funds. | Immediate | The virtual cash decrease could not be confirmed due to insufficient available funds. The request has been placed in the backlog queue and will automatically move to CONFIRMED once sufficient funds arrive. |
| **VIRTUAL_CASH_DECREASE.CANCELLED** | Cancellation | Immediate | The virtual cash decrease has been cancelled. Only possible if the decrease was in ISSUED or QUEUED state. |


## Virtual cash lifecycle

Virtual cash increases and decreases follow defined lifecycles with state transitions. The following diagrams show typical flows:

### Increase lifecycle

```
Increase requested
     ↓
VIRTUAL_CASH_INCREASE.ISSUED
     ↓
Increase confirmed
     ↓
VIRTUAL_CASH_INCREASE.CONFIRMED
     ↓
Balance available for trading
```

### Decrease lifecycle

```
Decrease requested
     ↓
VIRTUAL_CASH_DECREASE.ISSUED
     ↓
Either:
  → VIRTUAL_CASH_DECREASE.CONFIRMED (sufficient funds)
  → VIRTUAL_CASH_DECREASE.QUEUED (insufficient funds, enters backlog)
     ↓
If queued and funds arrive later:
  → VIRTUAL_CASH_DECREASE.CONFIRMED
     ↓
Decrease complete

(Alternative: VIRTUAL_CASH_DECREASE.CANCELLED at ISSUED or QUEUED state)
```

## Virtual cash event details

### VIRTUAL_CASH_INCREASE.ISSUED

Sent when a virtual cash increase request has been received and is awaiting confirmation.

```json
{
  "id": "3f6c1c4a-8e2d-4b9f-a1c3-2e5d7f9b4a6c",
  "created_at": "2024-02-15T10:30:00.00Z",
  "type": "VIRTUAL_CASH_INCREASE.ISSUED",
  "object": {
    "id": "increase-12345abc",
    "account_group_id": "acg-67890def",
    "amount": "1000.00",
    "currency": "EUR",
    "status": "ISSUED",
    "created_at": "2024-02-15T10:30:00.000Z",
    "updated_at": "2024-02-15T10:30:00.000Z"
  },
  "webhook_id": "webhook-abc123def456"
}
```

### VIRTUAL_CASH_INCREASE.CONFIRMED

Sent when the virtual cash increase has been confirmed and the balance is now available for trading.

```json
{
  "id": "4a7d2d5b-9f3e-5c0a-b2d4-3f6e8a0c5b7d",
  "created_at": "2024-02-15T10:30:15.00Z",
  "type": "VIRTUAL_CASH_INCREASE.CONFIRMED",
  "object": {
    "id": "increase-12345abc",
    "account_group_id": "acg-67890def",
    "amount": "1000.00",
    "currency": "EUR",
    "status": "CONFIRMED",
    "created_at": "2024-02-15T10:30:00.000Z",
    "updated_at": "2024-02-15T10:30:15.000Z"
  },
  "webhook_id": "webhook-abc123def456"
}
```

### VIRTUAL_CASH_DECREASE.ISSUED

Sent when a virtual cash decrease request has been received and is awaiting confirmation or queuing.

### VIRTUAL_CASH_DECREASE.CONFIRMED

Sent when a virtual cash decrease has been confirmed. The balance has been removed from the account. This may occur immediately if funds were available, or after the request was queued and funds later arrived.

### VIRTUAL_CASH_DECREASE.QUEUED

Sent when a virtual cash decrease could not be confirmed due to insufficient available funds. The request has entered the backlog queue and will automatically transition to CONFIRMED once sufficient funds arrive.

### VIRTUAL_CASH_DECREASE.CANCELLED

Sent when a virtual cash decrease has been cancelled. Only possible if the decrease was in ISSUED or QUEUED state at the time of cancellation.

## Field descriptions

| Field | Type | Description |
|  --- | --- | --- |
| `id` | string (UUID). | Unique identifier for this webhook event. |
| `created_at` | string (ISO 8601 timestamp). | When the webhook event was created (UTC). |
| `type` | string | Event type: `VIRTUAL_CASH_INCREASE.ISSUED`, `VIRTUAL_CASH_INCREASE.CONFIRMED`, `VIRTUAL_CASH_DECREASE.ISSUED`, `VIRTUAL_CASH_DECREASE.CONFIRMED`, `VIRTUAL_CASH_DECREASE.QUEUED`, or `VIRTUAL_CASH_DECREASE.CANCELLED`. |
| `object.id` | string | Virtual cash operation ID — use this to retrieve the operation status via the API. |
| `object.account_group_id` | string (UUID). | Account group ID associated with this virtual cash operation. |
| `object.amount` | string (decimal). | Amount of the operation in the specified currency. |
| `object.currency` | string | Currency of the operation (e.g., `EUR`). |
| `object.status` | string | Current operation status: `ISSUED`, `CONFIRMED`, `QUEUED`, or `CANCELLED`. |
| `object.created_at` | string (ISO 8601 timestamp). | When the operation was created (UTC). |
| `object.updated_at` | string (ISO 8601 timestamp). | When the operation was last updated (UTC). |
| `webhook_id` | string (UUID). | Unique identifier for this webhook subscription — used for debugging. |


## Recommended workflow

Follow these steps to implement virtual cash tracking via webhooks:

1. **Set up webhook handler**
Create an HTTP endpoint to listen for incoming webhooks. Endpoint must validate webhook signatures and respond with HTTP 200 within 30 seconds.
For more information, refer to [Implementing webhooks](/products/tol/getting_started/implementing_webhooks)
2. **Subscribe to VIRTUAL_CASH events**
Call `POST /webhooks` with event types: `VIRTUAL_CASH_INCREASE.ISSUED`, `VIRTUAL_CASH_INCREASE.CONFIRMED`, `VIRTUAL_CASH_DECREASE.ISSUED`, `VIRTUAL_CASH_DECREASE.CONFIRMED`, `VIRTUAL_CASH_DECREASE.QUEUED`, `VIRTUAL_CASH_DECREASE.CANCELLED`.
For more information, refer to [Webhook subscription](/api/webhook-subscriptions/create_webhook)
3. **Initiate virtual cash operation**
Call `POST /virtual_cash_balances/increases` or `POST /virtual_cash_balances/decreases` to begin the operation. Receive an operation ID in the response.
4. **Handle VIRTUAL_CASH.* webhooks**
Your webhook handler receives events at each state transition. Track the operation progress in your application state. For decreases that move to QUEUED, monitor for subsequent CONFIRMED events.
5. **Handle queued decreases (optional)**
If a decrease enters QUEUED state, your application may notify the end user that the operation is pending. When funds arrive and the request moves to CONFIRMED, notify the user that the balance has been updated.