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.

Using webhooks eliminates the need for polling, reducing API calls and providing faster updates.

Setting Up Webhooks

Create a webhook endpoint to start receiving events:

Bash
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

EventDescription
invoice.createdA new invoice was created
invoice.updatedAn invoice was updated
invoice.submittedInvoice successfully submitted to ZIMRA
invoice.failedInvoice submission to ZIMRA failed
invoice.voidedAn invoice was voided

Receipt Events

EventDescription
receipt.createdA new receipt was created
receipt.voidedA receipt was voided

Customer Events

EventDescription
customer.createdA new customer was created
customer.updatedA customer was updated
customer.deletedA customer was deleted

Webhook Payload

Webhook payloads follow a consistent structure:

Webhook Payload
{
  "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"
  }
}
FieldTypeDescription
idstringUnique event ID
typestringEvent type (e.g., invoice.submitted)
created_atstringISO 8601 timestamp
dataobjectEvent-specific data

Signature Verification

Always verify webhook signatures to ensure requests come from VasBox. Each webhook includes an X-VasBox-Signature header.

PHP

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)

JavaScript
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

Never skip signature verification in production. Unsigned requests may be from malicious sources.

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.