Skip to content

Webhooks

YeboVerify can send webhook notifications to your server when verification events occur. This is useful for async verification flows or for keeping your system in sync with verification results.

Setting Up Webhooks

Configure Your Webhook URL

bash
curl -X PUT https://api.yeboverify.com/v1/account/webhook \
  -H "X-API-Key: your_api_key" \
  -H "Content-Type: application/json" \
  -d '{
    "webhookUrl": "https://yourapp.com/webhooks/yeboverify",
    "webhookSecret": "whsec_your_secret_here"
  }'

Webhook Secret

The webhook secret is used to sign webhook payloads using HMAC-SHA256. Always verify the signature to ensure the webhook is from YeboVerify.


Webhook Events

verification.completed

Sent when a verification is completed (approved, rejected, or needs review).

Payload:

json
{
  "event": "verification.completed",
  "verificationId": "vrf_id_abc123xyz",
  "externalRef": "user_123",
  "status": "completed",
  "decision": "approved",
  "confidence": "high",
  "faceScore": 92.3,
  "ocrConfidence": 85,
  "extractedData": {
    "surname": "SMITH",
    "names": "JOHN MICHAEL",
    "dateOfBirth": "1990-05-15",
    "idNumber": "9005151234567",
    "documentType": "NATIONAL_ID"
  },
  "timestamp": "2024-01-15T12:00:05.000Z"
}

Payload Fields:

FieldTypeDescription
eventstringEvent type (verification.completed)
verificationIdstringUnique verification ID
externalRefstringYour reference ID (if provided)
statusstringcompleted, failed, or needs_review
decisionstringapproved, rejected, or needs_review
confidencestringhigh, medium, or low
faceScorenumberFace similarity score (0-100)
ocrConfidencenumberOCR confidence (0-100)
extractedDataobjectExtracted document data
timestampstringISO 8601 timestamp

Webhook Signature Verification

All webhook requests include a signature header for verification:

X-Webhook-Signature: sha256=d5a1e2b3c4f5...

Node.js Verification

javascript
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
  
  const actualSignature = signature.replace('sha256=', '');
  
  return crypto.timingSafeEqual(
    Buffer.from(expectedSignature),
    Buffer.from(actualSignature)
  );
}

// Express middleware
app.post('/webhooks/yeboverify', express.json(), (req, res) => {
  const signature = req.headers['x-webhook-signature'];
  const webhookSecret = process.env.YEBOVERIFY_WEBHOOK_SECRET;
  
  if (!verifyWebhookSignature(req.body, signature, webhookSecret)) {
    console.error('Invalid webhook signature');
    return res.status(401).send('Invalid signature');
  }
  
  const event = req.body;
  
  switch (event.event) {
    case 'verification.completed':
      handleVerificationCompleted(event);
      break;
    default:
      console.log('Unknown event type:', event.event);
  }
  
  res.status(200).send('OK');
});

function handleVerificationCompleted(event) {
  console.log(`Verification ${event.verificationId} completed`);
  console.log(`Decision: ${event.decision}`);
  console.log(`User: ${event.externalRef}`);
  
  // Update your database, send notifications, etc.
}

Python Verification

python
import hmac
import hashlib
import json
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = 'your_webhook_secret'

def verify_signature(payload, signature, secret):
    expected = hmac.new(
        secret.encode(),
        json.dumps(payload, separators=(',', ':')).encode(),
        hashlib.sha256
    ).hexdigest()
    
    actual = signature.replace('sha256=', '')
    
    return hmac.compare_digest(expected, actual)


@app.route('/webhooks/yeboverify', methods=['POST'])
def handle_webhook():
    signature = request.headers.get('X-Webhook-Signature')
    
    if not signature:
        abort(401)
    
    payload = request.json
    
    if not verify_signature(payload, signature, WEBHOOK_SECRET):
        abort(401)
    
    event_type = payload.get('event')
    
    if event_type == 'verification.completed':
        handle_verification_completed(payload)
    
    return 'OK', 200


def handle_verification_completed(event):
    print(f"Verification {event['verificationId']} completed")
    print(f"Decision: {event['decision']}")
    print(f"User: {event.get('externalRef')}")
    
    # Update your database, send notifications, etc.

Webhook Retry Policy

If your webhook endpoint returns an error (non-2xx status code) or times out, YeboVerify will retry the webhook:

AttemptDelay
1Immediate
230 seconds
32 minutes
410 minutes
51 hour

After 5 failed attempts, the webhook is marked as failed and no further retries are attempted.


Best Practices

1. Return 200 Quickly

Always return a 200 OK response as quickly as possible. Process the webhook data asynchronously.

javascript
app.post('/webhooks/yeboverify', (req, res) => {
  // Respond immediately
  res.status(200).send('OK');
  
  // Process asynchronously
  processWebhookAsync(req.body).catch(console.error);
});

2. Handle Duplicate Events

Webhooks may be delivered more than once. Use the verificationId to deduplicate:

javascript
const processedEvents = new Set();

function handleWebhook(event) {
  if (processedEvents.has(event.verificationId)) {
    console.log('Duplicate event, skipping');
    return;
  }
  
  processedEvents.add(event.verificationId);
  // Process the event...
}

3. Verify Signatures

Always verify the webhook signature before processing. This prevents spoofed webhooks.

4. Use HTTPS

Always use HTTPS for your webhook endpoint. YeboVerify will not send webhooks to HTTP URLs.

5. Handle Timeouts

Your webhook endpoint should respond within 30 seconds. If processing takes longer, use a queue:

javascript
const { Queue } = require('bullmq');

const webhookQueue = new Queue('webhooks');

app.post('/webhooks/yeboverify', async (req, res) => {
  // Add to queue for async processing
  await webhookQueue.add('verification.completed', req.body);
  
  res.status(200).send('OK');
});

Testing Webhooks

Using ngrok for Local Development

  1. Install ngrok: npm install -g ngrok
  2. Start your local server: npm run dev
  3. Expose it: ngrok http 3000
  4. Update your webhook URL to the ngrok URL

Manual Webhook Test

You can simulate a webhook for testing:

bash
curl -X POST http://localhost:3000/webhooks/yeboverify \
  -H "Content-Type: application/json" \
  -H "X-Webhook-Signature: sha256=test_signature" \
  -d '{
    "event": "verification.completed",
    "verificationId": "vrf_test_123",
    "status": "completed",
    "decision": "approved",
    "confidence": "high",
    "faceScore": 92.3,
    "timestamp": "2024-01-15T12:00:00.000Z"
  }'