Overview

Instead of polling the API to check transaction status, configure a webhook URL on your server and Betavend will push events to you as they happen. Webhook delivery is guaranteed with automatic retries.

💡

Configure your webhook URL at business.betavend.com/webhooks. You can register multiple URLs for different event types.

Event Types

EventWhen it fires
transaction.completedA service purchase was successfully delivered
transaction.failedA transaction failed and wallet was auto-reversed
transaction.processingA transaction is being processed by the provider
wallet.creditedWallet was topped up via bank transfer
wallet.debitedWallet was debited for a purchase
wallet.reversedA failed transaction was reversed back to wallet

Payload Format

All webhook events share the same envelope structure:

transaction.completed payload
POST https://your-server.com/webhook
Content-Type: application/json
X-Betavend-Signature: sha256=abc123...
X-Betavend-Event: transaction.completed

{
  "event": "transaction.completed",
  "id": "evt_abc123",
  "created_at": "2026-05-02T14:00:05Z",
  "data": {
    "reference": "BV-20260502-001",
    "service_type": "data",
    "network": "mtn",
    "recipient": "08012345678",
    "amount": 550,
    "status": "delivered",
    "delivered_at": "2026-05-02T14:00:05Z"
  }
}

Signature Verification

Every webhook includes an X-Betavend-Signature header. Always verify this before processing:

Verify signature — Node.js
const crypto = require('crypto');

function verifyWebhook(payload, signature, secret) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(payload, 'utf8')
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(expected),
    Buffer.from(signature)
  );
}

// In your Express handler:
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-betavend-signature'];
  if (!verifyWebhook(req.body, sig, process.env.BETAVEND_WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }

  const event = JSON.parse(req.body);
  // Process event...
  res.json({ received: true });
});
Verify signature — PHP
$payload   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_BETAVEND_SIGNATURE'] ?? '';
$secret    = getenv('BETAVEND_WEBHOOK_SECRET');

$expected = 'sha256=' . hash_hmac('sha256', $payload, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(400);
    exit('Invalid signature');
}

$event = json_decode($payload, true);
// Process $event...

Retry Policy

If your endpoint returns anything other than a 2xx status, Betavend retries with exponential backoff:

AttemptDelay
1st retry30 seconds
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry8 hours

After 5 failed attempts the event is marked as dead. You can manually replay failed events from business.betavend.com/webhooks.

Best Practices