Webhooks
Receive real-time notifications when events occur in your VasBox account.
Webhooks allow your application to receive real-time notifications when events occur in your VasBox account, such as invoice submissions or ZIMRA status updates.
Setting Up Webhooks
Create a webhook endpoint to start receiving events:
curl -X POST https://api.vasbox.co.zw/v1/webhooks \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://yourapp.com/webhooks/vasbox",
"events": ["invoice.submitted", "invoice.failed"],
"description": "Production webhook endpoint"
}'
Requirements
- Your endpoint must be publicly accessible via HTTPS
- Respond with a 2xx status code within 30 seconds
- Handle duplicate events idempotently
- Verify webhook signatures for security
Event Types
Subscribe to specific events based on your integration needs:
Invoice Events
| Event | Description |
|---|---|
invoice.created | A new invoice was created |
invoice.updated | An invoice was updated |
invoice.submitted | Invoice successfully submitted to ZIMRA |
invoice.failed | Invoice submission to ZIMRA failed |
invoice.voided | An invoice was voided |
Receipt Events
| Event | Description |
|---|---|
receipt.created | A new receipt was created |
receipt.voided | A receipt was voided |
Customer Events
| Event | Description |
|---|---|
customer.created | A new customer was created |
customer.updated | A customer was updated |
customer.deleted | A customer was deleted |
Webhook Payload
Webhook payloads follow a consistent structure:
{
"id": "evt_abc123",
"type": "invoice.submitted",
"created_at": "2024-01-15T10:30:00Z",
"data": {
"id": "inv_xyz789",
"number": "INV-2024-0001",
"status": "submitted",
"fiscal_code": "ZW-2024-ABC123",
"total": 5750.00,
"customer_id": "cust_123"
}
}
| Field | Type | Description |
|---|---|---|
| id | string | Unique event ID |
| type | string | Event type (e.g., invoice.submitted) |
| created_at | string | ISO 8601 timestamp |
| data | object | Event-specific data |
Signature Verification
Always verify webhook signatures to ensure requests come from VasBox. Each webhook includes an X-VasBox-Signature header.
PHP
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_VASBOX_SIGNATURE'];
$secret = env('VASBOX_WEBHOOK_SECRET');
$expectedSignature = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process the webhook event
switch ($event['type']) {
case 'invoice.submitted':
handleInvoiceSubmitted($event['data']);
break;
case 'invoice.failed':
handleInvoiceFailed($event['data']);
break;
}
http_response_code(200);
JavaScript (Express)
import crypto from 'crypto';
import express from 'express';
const app = express();
app.use(express.raw({ type: 'application/json' }));
app.post('/webhooks/vasbox', (req, res) => {
const payload = req.body;
const signature = req.headers['x-vasbox-signature'];
const secret = process.env.VASBOX_WEBHOOK_SECRET;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
if (signature !== expectedSignature) {
return res.status(401).send('Invalid signature');
}
const event = JSON.parse(payload);
// Process the webhook event
switch (event.type) {
case 'invoice.submitted':
handleInvoiceSubmitted(event.data);
break;
case 'invoice.failed':
handleInvoiceFailed(event.data);
break;
}
res.status(200).send('OK');
});
Security
Best Practices
Respond Quickly
Return a 2xx response as soon as you receive the webhook. Process the event asynchronously using a queue.
Handle Duplicates
Webhooks may be delivered multiple times. Use the event id to deduplicate events.
Retry Behavior
If your endpoint returns a non-2xx status, we'll retry with exponential backoff:
- Retry 1: 1 minute
- Retry 2: 5 minutes
- Retry 3: 30 minutes
- Retry 4: 2 hours
- Retry 5: 24 hours
Monitor Deliveries
Check webhook delivery status in your dashboard. Failed deliveries are logged with error details.