Reservations
Holds and authorizations for two-phase transactions
Reservations are temporary holds on wallet funds that enable two-phase transaction patterns. They're essential for scenarios where you need to guarantee funds before completing an operation, such as payment authorizations, order processing, or gaming wagers.
Reservation Structure
| Field | Type | Description |
|---|---|---|
id | string | Unique identifier (UUID) |
wallet_id | string | Wallet being reserved from |
asset_code | string | Asset type being reserved |
amount | string | Reserved amount |
status | enum | Current state (see below) |
expires_at | timestamp | Auto-release time |
metadata | object | Custom key-value pairs |
created_at | timestamp | Creation timestamp |
updated_at | timestamp | Last state change |
Reservation States
Reservations follow a defined state machine:
┌─────────────────────┐
│ │
create() │ PENDING │
───────────────▶│ │
│ Funds are held │
└─────────────────────┘
│
┌────────────────────┼────────────────────┐
│ │ │
▼ ▼ ▼
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ │ │ │ │ │
│ COMMITTED │ │ RELEASED │ │ EXPIRED │
│ │ │ │ │ │
│ Funds debited │ │ Funds returned │ │ Auto-released │
│ from wallet │ │ to available │ │ after timeout │
└─────────────────┘ └─────────────────┘ └─────────────────┘
commit() release() (automatic)State Descriptions
| State | Description | Funds Location |
|---|---|---|
PENDING | Active hold | Reserved (not available) |
COMMITTED | Permanently deducted | Removed from wallet |
RELEASED | Hold cancelled | Returned to available |
EXPIRED | Auto-released after timeout | Returned to available |
All terminal states (COMMITTED, RELEASED, EXPIRED) are final. Once a reservation reaches a terminal state, it cannot be modified.
Use Cases
Payment Authorization
1. User initiates checkout for $50
2. Create reservation for $50 → PENDING
3. User confirms payment
4. Commit reservation → COMMITTED (funds deducted)
Alternative: User cancels
4. Release reservation → RELEASED (funds returned)Gaming Wagers
1. Player places $10 bet
2. Create reservation for $10 → PENDING
3. Game resolves
- Player wins: Release reservation, credit winnings
- Player loses: Commit reservation (house keeps funds)Order Fulfillment
1. Customer orders items totaling $75
2. Create reservation for $75 → PENDING
3. Items ship
4. Commit reservation → COMMITTED
Alternative: Item out of stock
4. Partial release, adjust reservation amountCreating a Reservation
curl -X POST https://api.phoenixwallet.io/v1/reservations \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"wallet_id": "wal_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"asset_code": "USD",
"amount": "5000",
"intent": "purchase",
"expires_at": "2024-01-16T10:30:00Z",
"metadata": {
"order_id": "ord_12345",
"description": "Shopping cart checkout"
},
"idempotency_key": "reserve_order_12345"
}'Response:
{
"id": "rsv_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"wallet_id": "wal_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"asset_code": "USD",
"amount": "5000",
"status": "PENDING",
"intent": "purchase",
"expires_at": "2024-01-16T10:30:00Z",
"metadata": {
"order_id": "ord_12345",
"description": "Shopping cart checkout"
},
"lots": [
{
"lot_id": "lot_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"amount": "5000"
}
],
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z"
}Committing a Reservation
When you're ready to finalize the transaction:
curl -X POST https://api.phoenixwallet.io/v1/reservations/rsv_01HV8X.../commit \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"amount": "5000",
"metadata": {
"payment_reference": "pay_98765"
}
}'You can commit a partial amount. If the original reservation was for $50 but the final charge is $45, commit only $45 and the remaining $5 is automatically released.
Releasing a Reservation
To cancel a hold and return funds to available:
curl -X POST https://api.phoenixwallet.io/v1/reservations/rsv_01HV8X.../release \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{
"reason": "Order cancelled by customer"
}'Reservation Expiry
Reservations automatically expire if not committed or released within the specified time:
{
"expires_at": "2024-01-16T10:30:00Z"
}When a reservation expires:
- Status changes to
EXPIRED - Reserved funds return to available balance
- A
reservation.expiredevent is emitted
Always set appropriate expiration times. Short expirations (15-30 minutes) work well for checkout flows. Longer expirations (24-72 hours) suit order fulfillment patterns.
Lot Selection for Reservations
When creating a reservation, Phoenix Wallet selects lots based on:
- Policy compatibility - Lots must allow the specified intent
- Available balance - Lots must have sufficient unreserved funds
- Depletion order - FIFO, FEFO, or custom ordering
The reservation response includes which lots were selected:
{
"lots": [
{
"lot_id": "lot_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"amount": "3000"
},
{
"lot_id": "lot_02HV8X9Y2KPQRS3T4UV5WX6YZ8",
"amount": "2000"
}
]
}Querying Reservations
List Active Reservations
curl "https://api.phoenixwallet.io/v1/wallets/wal_01HV8X.../reservations?status=PENDING" \
-H "Authorization: Bearer $API_KEY"Get Reservation Details
curl "https://api.phoenixwallet.io/v1/reservations/rsv_01HV8X..." \
-H "Authorization: Bearer $API_KEY"Impact on Balances
Reservations affect the reserved portion of wallet balances:
{
"wallet_id": "wal_01HV8X9Y2KPQRS3T4UV5WX6YZ7",
"balances": [
{
"asset_code": "USD",
"available": "10000",
"reserved": "5000",
"total": "15000"
}
]
}In this example:
- User has $150 total
- $50 is reserved (held for pending transactions)
- $100 is available for new transactions