Events
Event streaming and webhook integration
Phoenix Wallet provides real-time event streaming and webhook delivery for all ledger operations. Events enable you to build reactive systems that respond to balance changes, expirations, and other wallet activities.
Event Streaming
Subscribe to a real-time stream of events using Server-Sent Events (SSE).
GET /events/streamQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
types | string | all | Comma-separated event types to subscribe to |
wallet_id | string | - | Filter to specific wallet |
from_sequence | string | - | Resume from a specific sequence number |
Example Request
curl -N "{{BASE_URL}}/events/stream?types=wallet.credited,wallet.debited" \
-H "Authorization: Bearer {{API_KEY}}" \
-H "Accept: text/event-stream"Example Stream Output
event: wallet.credited
id: seq_000000000001
data: {"id":"evt_abc123","type":"wallet.credited","wallet_id":"wal_abc123def456","data":{"amount":"100.00","asset":"POINTS","lot_id":"lot_xyz789"},"created_at":"2024-01-15T10:30:00Z"}
event: wallet.debited
id: seq_000000000002
data: {"id":"evt_def456","type":"wallet.debited","wallet_id":"wal_abc123def456","data":{"amount":"25.00","asset":"POINTS","transfer_id":"txf_lmn123"},"created_at":"2024-01-15T10:35:00Z"}
event: heartbeat
id: seq_000000000003
data: {"timestamp":"2024-01-15T10:40:00Z"}Connection Notes
- The stream sends a heartbeat every 30 seconds to keep the connection alive
- If disconnected, use
from_sequenceto resume without missing events - Events are delivered in order within each wallet, but may be interleaved across wallets
Webhooks
Configure webhook endpoints to receive event notifications via HTTP POST.
Create Webhook
POST /webhooksRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | Yes | HTTPS endpoint to receive events |
events | array | Yes | Event types to subscribe to (or ["*"] for all) |
secret | string | No | Shared secret for signature verification (auto-generated if not provided) |
metadata | object | No | Custom key-value pairs |
Example Request
curl -X POST {{BASE_URL}}/webhooks \
-H "Authorization: Bearer {{API_KEY}}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: {{IDEMPOTENCY_KEY}}" \
-d '{
"url": "https://your-app.com/webhooks/phoenix-wallet",
"events": [
"wallet.credited",
"wallet.debited",
"reservation.created",
"reservation.committed",
"lot.expired"
],
"metadata": {
"environment": "production"
}
}'Example Response
{
"data": {
"id": "whk_abc123def456",
"url": "https://your-app.com/webhooks/phoenix-wallet",
"events": [
"wallet.credited",
"wallet.debited",
"reservation.created",
"reservation.committed",
"lot.expired"
],
"secret": "whsec_aBcDeFgHiJkLmNoPqRsTuVwXyZ123456",
"status": "active",
"metadata": {
"environment": "production"
},
"created_at": "2024-01-15T10:00:00Z"
}
}Webhook Payload
When an event occurs, Phoenix Wallet sends an HTTP POST to your endpoint.
Headers
| Header | Description |
|---|---|
Content-Type | application/json |
X-Phoenix-Signature | HMAC-SHA256 signature of the payload |
X-Phoenix-Timestamp | Unix timestamp of the request |
X-Phoenix-Event-ID | Unique event identifier |
X-Phoenix-Event-Type | Event type (e.g., wallet.credited) |
Example Payload
{
"id": "evt_abc123def456",
"type": "wallet.credited",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"wallet_id": "wal_abc123def456",
"amount": "100.00",
"asset": "POINTS",
"credit_id": "crd_xyz789abc123",
"lot_id": "lot_mno456pqr789",
"reference": "purchase_order_789",
"balance_after": {
"available": "1600.00",
"reserved": "200.00",
"total": "1800.00"
}
}
}Verifying Webhook Signatures
Always verify webhook signatures to ensure requests are from Phoenix Wallet.
const crypto = require('crypto');
function verifyWebhookSignature(payload, signature, timestamp, secret) {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
// Use timing-safe comparison
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expectedSignature)
);
}
// In your webhook handler
app.post('/webhooks/phoenix-wallet', (req, res) => {
const signature = req.headers['x-phoenix-signature'];
const timestamp = req.headers['x-phoenix-timestamp'];
const payload = JSON.stringify(req.body);
if (!verifyWebhookSignature(payload, signature, timestamp, WEBHOOK_SECRET)) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process the event
const event = req.body;
console.log(`Received event: ${event.type}`);
res.status(200).json({ received: true });
});Webhook Retry Policy
If your endpoint returns a non-2xx response, Phoenix Wallet retries with exponential backoff:
| Attempt | Delay |
|---|---|
| 1 | Immediate |
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
| 7 | 24 hours |
After 7 failed attempts, the webhook is marked as failed and the event is logged for manual review.
List Webhooks
GET /webhooksExample Request
curl -X GET {{BASE_URL}}/webhooks \
-H "Authorization: Bearer {{API_KEY}}"Example Response
{
"data": [
{
"id": "whk_abc123def456",
"url": "https://your-app.com/webhooks/phoenix-wallet",
"events": ["wallet.credited", "wallet.debited"],
"status": "active",
"created_at": "2024-01-15T10:00:00Z"
}
]
}Update Webhook
PATCH /webhooks/{{WEBHOOK_ID}}Request Body
| Field | Type | Required | Description |
|---|---|---|---|
url | string | No | New endpoint URL |
events | array | No | Replace subscribed events |
status | string | No | Set to active or disabled |
Example Request
curl -X PATCH {{BASE_URL}}/webhooks/{{WEBHOOK_ID}} \
-H "Authorization: Bearer {{API_KEY}}" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: {{IDEMPOTENCY_KEY}}" \
-d '{
"events": ["wallet.credited", "wallet.debited", "lot.expired"],
"status": "active"
}'Delete Webhook
DELETE /webhooks/{{WEBHOOK_ID}}Example Request
curl -X DELETE {{BASE_URL}}/webhooks/{{WEBHOOK_ID}} \
-H "Authorization: Bearer {{API_KEY}}" \
-H "Idempotency-Key: {{IDEMPOTENCY_KEY}}"Event Types
Wallet Events
| Event Type | Description |
|---|---|
wallet.created | A new wallet was created |
wallet.updated | Wallet metadata or policies were updated |
wallet.suspended | Wallet was suspended |
wallet.reactivated | Suspended wallet was reactivated |
wallet.credited | Funds were added to the wallet |
wallet.debited | Funds were removed from the wallet |
Reservation Events
| Event Type | Description |
|---|---|
reservation.created | A new reservation was created |
reservation.committed | Reservation was committed (funds debited) |
reservation.released | Reservation was released (funds returned) |
reservation.expired | Reservation expired automatically |
reservation.extended | Reservation expiration was extended |
Transfer Events
| Event Type | Description |
|---|---|
transfer.created | A transfer was completed |
Lot Events
| Event Type | Description |
|---|---|
lot.created | A new lot was created |
lot.updated | Lot attributes were updated |
lot.expired | Lot expired (automatic or manual) |
lot.depleted | Lot balance reached zero |
Get Event
Retrieve a specific event by ID.
GET /events/{{EVENT_ID}}Example Request
curl -X GET {{BASE_URL}}/events/{{EVENT_ID}} \
-H "Authorization: Bearer {{API_KEY}}"Example Response
{
"data": {
"id": "evt_abc123def456",
"type": "wallet.credited",
"api_version": "2024-01-01",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"wallet_id": "wal_abc123def456",
"amount": "100.00",
"asset": "POINTS",
"credit_id": "crd_xyz789abc123"
},
"delivery_attempts": [
{
"webhook_id": "whk_abc123def456",
"status": "delivered",
"response_code": 200,
"attempted_at": "2024-01-15T10:30:01Z"
}
]
}
}List Events
Retrieve a paginated list of events.
GET /eventsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Number of results (max 100) |
cursor | string | - | Pagination cursor |
type | string | - | Filter by event type |
wallet_id | string | - | Filter by wallet |
from_date | string | - | Events after this date (ISO 8601) |
to_date | string | - | Events before this date (ISO 8601) |
Example Request
curl -X GET "{{BASE_URL}}/events?type=wallet.credited&wallet_id={{WALLET_ID}}&limit=10" \
-H "Authorization: Bearer {{API_KEY}}"Example Response
{
"data": [
{
"id": "evt_abc123def456",
"type": "wallet.credited",
"wallet_id": "wal_abc123def456",
"created_at": "2024-01-15T10:30:00Z"
},
{
"id": "evt_def456ghi789",
"type": "wallet.credited",
"wallet_id": "wal_abc123def456",
"created_at": "2024-01-14T15:00:00Z"
}
],
"pagination": {
"has_more": true,
"next_cursor": "eyJpZCI6ImV2dF9kZWY0NTZnaGk3ODkifQ=="
}
}