Webhooks

Set up real-time event notifications for verifications, AML screenings, deepfake scans, and KYT alerts using webhooks.

Webhooks

Receive real-time HTTP notifications when events occur in your VeriPlus account. Webhooks eliminate the need to poll APIs for status updates.

Overview

Webhooks send HTTP POST requests to your server when:

  • Verification completes
  • AML screening finds matches
  • Deepfake scan detects manipulation
  • KYT wallet monitoring triggers alert
  • Credit balance runs low

Setting Up Webhooks

Create Webhook Endpoint

POST/api/v3/webhooks🔒 Auth Required0

Create a webhook endpoint

Register a webhook URL to receive event notifications.

const response = await fetch('https://api.veriplus.co.uk/api/v3/webhooks', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${apiKey}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    url: 'https://yourdomain.com/webhooks/veriplus',
    events: [
      'verification.completed',
      'aml.match_found',
      'deepfake.scan_completed',
      'kyt.high_risk_detected'
    ],
    secret: 'whsec_' + crypto.randomUUID(),
    description: 'Production webhook endpoint'
  })
});
 
const data = await response.json();
console.log('Webhook ID:', data.data.webhookId);
console.log('Secret:', data.data.secret); // Save this!

Response

{
  "success": true,
  "data": {
    "webhookId": "wh_abc123xyz",
    "url": "https://yourdomain.com/webhooks/veriplus",
    "events": [
      "verification.completed",
      "aml.match_found",
      "deepfake.scan_completed",
      "kyt.high_risk_detected"
    ],
    "secret": "whsec_1a2b3c4d5e6f",
    "status": "ACTIVE",
    "createdAt": "2024-01-15T10:30:00Z"
  }
}

Save Your Secret

The webhook secret is only shown once. Store it securely - you'll need it to verify webhook signatures.

Receiving Webhooks

Request Format

VeriPlus sends POST requests to your webhook URL:

POST /webhooks/veriplus HTTP/1.1
Host: yourdomain.com
Content-Type: application/json
X-Veriplus-Signature: sha256=a1b2c3d4e5f6...
X-Veriplus-Event: verification.completed
X-Veriplus-Delivery: del_xyz789
 
{
  "event": "verification.completed",
  "timestamp": "2024-01-15T10:32:14Z",
  "data": {
    "verificationId": "verif_abc123",
    "applicantId": "app_1234567890",
    "status": "COMPLETED",
    "result": "APPROVED"
  }
}

Headers

HeaderDescription
X-Veriplus-SignatureHMAC-SHA256 signature for verification
X-Veriplus-EventEvent type
X-Veriplus-DeliveryUnique delivery ID

Implementing Webhook Handler

const express = require('express');
const crypto = require('crypto');
 
const app = express();
app.use(express.json());
 
const WEBHOOK_SECRET = process.env.VERIPLUS_WEBHOOK_SECRET;
 
function verifySignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');
 
  return crypto.timingSafeEqual(
    Buffer.from(signature.replace('sha256=', '')),
    Buffer.from(expectedSignature)
  );
}
 
app.post('/webhooks/veriplus', (req, res) => {
  const signature = req.headers['x-veriplus-signature'];
  const event = req.headers['x-veriplus-event'];
  const payload = req.body;
 
  // Verify signature
  if (!verifySignature(payload, signature, WEBHOOK_SECRET)) {
    console.error('Invalid webhook signature');
    return res.status(401).json({ error: 'Invalid signature' });
  }
 
  // Process event
  console.log('Received event:', event);
 
  switch (event) {
    case 'verification.completed':
      handleVerificationCompleted(payload.data);
      break;
 
    case 'aml.match_found':
      handleAmlMatch(payload.data);
      break;
 
    case 'deepfake.scan_completed':
      handleDeepfakeScan(payload.data);
      break;
 
    case 'kyt.high_risk_detected':
      handleKytAlert(payload.data);
      break;
 
    default:
      console.log('Unknown event type:', event);
  }
 
  // Return 200 to acknowledge receipt
  res.status(200).json({ received: true });
});
 
function handleVerificationCompleted(data) {
  console.log('Verification completed:', data.verificationId);
  console.log('Result:', data.result);
 
  // Update your database, send email, etc.
  if (data.result === 'APPROVED') {
    // Activate customer account
  } else if (data.result === 'REJECTED') {
    // Notify compliance team
  }
}
 
function handleAmlMatch(data) {
  console.log('AML match found:', data.screeningId);
  console.log('Risk level:', data.riskLevel);
 
  // Alert compliance team for manual review
  if (data.riskLevel === 'CRITICAL') {
    // Send urgent notification
  }
}
 
app.listen(3000, () => {
  console.log('Webhook server listening on port 3000');
});

Response Requirements

Your endpoint MUST:

  • Return HTTP 200 status code
  • Respond within 5 seconds
  • Verify the signature before processing

Failure to respond: Webhook will be retried with exponential backoff (max 3 retries).

Event Types

Verification Events

EventDescriptionPayload Fields
verification.createdVerification startedverificationId, applicantId, profileType
verification.pending_uploadAwaiting user uploadverificationId, uploadUrl, expiresAt
verification.completedVerification finishedverificationId, status, result
verification.approvedAuto-approvedverificationId, result, checks
verification.rejectedAuto-rejectedverificationId, result, failureReasons
verification.manual_reviewNeeds human reviewverificationId, reviewReason

Example Payload:

{
  "event": "verification.completed",
  "timestamp": "2024-01-15T10:32:14Z",
  "data": {
    "verificationId": "verif_abc123",
    "applicantId": "app_1234567890",
    "status": "COMPLETED",
    "result": "APPROVED",
    "checks": {
      "document": "PASS",
      "faceMatch": "PASS"
    }
  }
}

AML Events

EventDescriptionPayload Fields
aml.screening_completedScreening finishedscreeningId, matchCount, riskLevel
aml.match_foundMatch detectedscreeningId, matches, riskLevel
aml.monitoring_alertNew match in monitoringmonitoringId, newMatches
aml.sanctions_alertSanctions match (critical)screeningId, sanctionsList

Example Payload:

{
  "event": "aml.match_found",
  "timestamp": "2024-01-15T10:32:14Z",
  "data": {
    "screeningId": "aml_abc123",
    "applicantId": "app_1234567890",
    "matchCount": 2,
    "riskLevel": "HIGH",
    "categories": ["PEP", "ADVERSE_MEDIA"]
  }
}

Deepfake Events

EventDescriptionPayload Fields
deepfake.scan_completedAnalysis finishedjobId, mediaType, isDeepfake
deepfake.deepfake_detectedHigh-confidence deepfakejobId, confidence, manipulationType
deepfake.job_failedAnalysis failedjobId, errorCode, errorMessage

Example Payload:

{
  "event": "deepfake.deepfake_detected",
  "timestamp": "2024-01-15T10:31:05Z",
  "data": {
    "jobId": "job_vid_xyz789",
    "mediaType": "VIDEO",
    "isDeepfake": true,
    "confidence": 89,
    "manipulationType": "FACE_SWAP",
    "recommendation": "REJECT"
  }
}

KYT Events

EventDescriptionPayload Fields
kyt.check_completedWallet check finishedcheckId, address, riskScore
kyt.high_risk_detectedRisk score above thresholdcheckId, riskScore, topRisks
kyt.sanctions_matchSanctioned addresscheckId, address, sanctionsList
kyt.monitoring_alertRisk change detectedmonitoringId, oldRiskScore, newRiskScore

Example Payload:

{
  "event": "kyt.high_risk_detected",
  "timestamp": "2024-01-15T10:30:00Z",
  "data": {
    "checkId": "kyt_abc123",
    "address": "1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
    "blockchain": "BTC",
    "riskScore": 72,
    "riskLevel": "HIGH",
    "topRisks": ["MIXER", "DARKNET_MARKETS"]
  }
}

System Events

EventDescriptionPayload Fields
credits.low_balanceCredit balance lowcurrentBalance, threshold
credits.depletedNo credits remainingorganizationId

Example Payload:

{
  "event": "credits.low_balance",
  "timestamp": "2024-01-15T10:00:00Z",
  "data": {
    "organizationId": "org_abc123",
    "currentBalance": 50,
    "threshold": 100,
    "message": "Your credit balance is running low. Purchase more credits to avoid service interruption."
  }
}

Managing Webhooks

List Webhooks

GET/api/v3/webhooks🔒 Auth Required0

List all webhook endpoints

const response = await fetch('https://api.veriplus.co.uk/api/v3/webhooks', {
  headers: {
    'Authorization': `Bearer ${apiKey}`
  }
});
 
const data = await response.json();
console.log('Webhooks:', data.data);

Update Webhook

PATCH/api/v3/webhooks/:id🔒 Auth Required0

Update webhook configuration

const response = await fetch(
  `https://api.veriplus.co.uk/api/v3/webhooks/${webhookId}`,
  {
    method: 'PATCH',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      events: [
        'verification.completed',
        'aml.match_found',
        'deepfake.scan_completed',
        'kyt.high_risk_detected',
        'credits.low_balance'
      ]
    })
  }
);

Delete Webhook

DELETE/api/v3/webhooks/:id🔒 Auth Required0

Delete webhook endpoint

const response = await fetch(
  `https://api.veriplus.co.uk/api/v3/webhooks/${webhookId}`,
  {
    method: 'DELETE',
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  }
);
 
if (response.ok) {
  console.log('Webhook deleted');
}

Test Webhook

POST/api/v3/webhooks/:id/test🔒 Auth Required0

Send test event to webhook

Send a test event to verify your webhook is working.

const response = await fetch(
  `https://api.veriplus.co.uk/api/v3/webhooks/${webhookId}/test`,
  {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      event: 'verification.completed'
    })
  }
);
 
const data = await response.json();
console.log('Test delivery ID:', data.data.deliveryId);
console.log('Response code:', data.data.responseCode);

Webhook Deliveries

View delivery logs for debugging:

GET/api/v3/webhooks/:id/deliveries🔒 Auth Required0

List webhook delivery attempts

const response = await fetch(
  `https://api.veriplus.co.uk/api/v3/webhooks/${webhookId}/deliveries`,
  {
    headers: {
      'Authorization': `Bearer ${apiKey}`
    }
  }
);
 
const data = await response.json();
data.data.forEach(delivery => {
  console.log(`${delivery.event}: ${delivery.responseCode} (${delivery.duration}ms)`);
});

Response:

{
  "success": true,
  "data": [
    {
      "deliveryId": "del_xyz789",
      "event": "verification.completed",
      "responseCode": 200,
      "duration": 234,
      "success": true,
      "timestamp": "2024-01-15T10:32:14Z"
    },
    {
      "deliveryId": "del_abc123",
      "event": "aml.match_found",
      "responseCode": 500,
      "duration": 5023,
      "success": false,
      "retryCount": 3,
      "timestamp": "2024-01-15T09:15:00Z"
    }
  ]
}

Retry Logic

Failed deliveries are retried automatically:

AttemptDelayTotal Elapsed
1Immediate0s
230 seconds30s
35 minutes5m 30s

After 3 failed attempts, the webhook is marked as failed and no further retries occur.

Best Practices

  1. Verify Signatures: Always verify X-Veriplus-Signature before processing
  2. Return 200 Quickly: Process events asynchronously, respond within 5 seconds
  3. Handle Duplicates: Same event may be delivered multiple times (use delivery ID for deduplication)
  4. Log Deliveries: Keep audit log of webhook events received
  5. Use HTTPS: Webhook URLs must use HTTPS (HTTP will be rejected)
  6. Monitor Failures: Set up alerts for failed webhook deliveries
  7. Test Thoroughly: Use test endpoint before going live

Security

  • HTTPS Only: All webhook URLs must use HTTPS
  • Signature Verification: Required to prevent spoofing
  • IP Allowlist: Optionally restrict to VeriPlus IPs (Enterprise)
  • Secret Rotation: Rotate webhook secrets every 90 days

VeriPlus Webhook IPs (for allowlisting):

203.0.113.10
203.0.113.11
203.0.113.12

Debugging

Webhook not receiving events?

  1. Check webhook is ACTIVE: GET /api/v3/webhooks
  2. Verify URL is publicly accessible
  3. Check firewall allows VeriPlus IPs
  4. Review delivery logs: GET /api/v3/webhooks/:id/deliveries
  5. Test webhook: POST /api/v3/webhooks/:id/test

Common Issues:

  • SSL certificate invalid → Fix SSL configuration
  • Timeout after 5 seconds → Process events asynchronously
  • Signature verification fails → Check secret matches

Next Steps

Ready to integrate?

Get your API key and start building in minutes.

Ready to get started?

Start with our free plan. No credit card required.

We value your privacy

We use cookies to enhance your browsing experience, serve personalized content, and analyze our traffic. By clicking "Accept All", you consent to our use of cookies. Read our Privacy Policy and Cookie Policy for more information.