Skip to main content

Overview

pawaPass sends webhook notifications to your configured URL when verification events occur. This allows you to track the entire lifecycle of a verification in real-time.

Setup

To configure your webhook URL and receive your signing secret key, contact us.

Events

Sent each time a verification’s status changes — from CREATED through STARTED, USER_DATA_COLLECTED, to a final state like APPROVED or DECLINED.This is the primary webhook for monitoring verification progress.
Sent when an agent manually corrects identity document data after a verification has concluded (e.g., fixing a typo in a name or date of birth).Does not fire during initial data collection.

Payload format

All webhook payloads follow the same structure:
{
  "notificationId": "a1b2c3d4-5678-9012-abcd-ef1234567890",
  "type": "VERIFICATION.STATUS_CHANGE",
  "object": "VERIFICATION",
  "createdAt": "2025-08-20T10:15:00.000Z",
  "data": {
    "id": "aB1cD2eF",
    "url": "https://app.pawapass.com/your-company/aB1cD2eF",
    "status": "APPROVED",
    "errorUrl": "https://your-website.com/error",
    "faceScan": {
      "ageEstimation": "OVER_25",
      "createdAt": "2025-08-20T09:30:00.000Z",
      "updatedAt": "2025-08-20T09:31:15.000Z"
    },
    "metadata": {
      "phoneNumber": "+260971234567",
      "jurisdiction": "ZM",
      "reason": "kyc-onboarding"
    },
    "createdAt": "2025-08-20T09:00:00.000Z",
    "createdBy": "[email protected]",
    "expiresAt": "2025-08-27T09:00:00.000Z",
    "updatedAt": "2025-08-20T10:15:00.000Z",
    "externalId": "user-zm-98765",
    "successUrl": "https://your-website.com/success",
    "supportUrl": "https://your-website.com/support",
    "requirements": [
      { "type": "DOCUMENT_SCAN" },
      { "type": "FACE_SCAN" }
    ],
    "identityDocument": {
      "type": "Government Issued Photo ID",
      "country": "Zambia",
      "serialNo": "1234567/89/0",
      "nationalNo": "Z98765432",
      "firstName": "Tisa",
      "lastName": "Banda",
      "dateOfBirth": "1997-05-10",
      "placeOfBirth": "Lusaka",
      "nationality": "ZM",
      "expiryAt": "2032-05-09",
      "issuedAt": "2022-05-10",
      "issuingAuthority": "Republic of Zambia",
      "placeOfIssue": "Lusaka",
      "createdAt": "2025-08-20T09:31:00.000Z",
      "updatedAt": "2025-08-20T10:15:00.000Z"
    }
  }
}

Age estimation values

The ageEstimation field on the face scan can be one of:
ValueAge
UNDER_8Under 8 years
OVER_8Over 8 years
OVER_13Over 13 years
OVER_16Over 16 years
OVER_18Over 18 years
OVER_21Over 21 years
OVER_25Over 25 years
OVER_30Over 30 years
UNKNOWNCould not be estimated

Signature verification

Webhooks include an X-Signature header containing a SHA256 HMAC signature of the raw request body, signed with your secret key. Verify this signature to confirm the webhook is authentic.
import { createHmac } from 'crypto';

function verifyWebhookSignature(
  requestBody: string,
  signature: string,
  secretKey: string
): boolean {
  const expected = createHmac('sha256', secretKey)
    .update(requestBody, 'utf-8')
    .digest('hex');
  return expected === signature;
}

// In your webhook handler:
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-signature'];
  const isValid = verifyWebhookSignature(req.rawBody, signature, SECRET_KEY);

  if (!isValid) {
    return res.status(401).send('Invalid signature');
  }

  const payload = JSON.parse(req.rawBody);
  // Process the webhook...

  res.status(200).send('OK');
});

Best practices

Verify the signature

Always validate the X-Signature header before processing the webhook payload.

Return 200 OK quickly

Process the webhook asynchronously if needed. Any non-2xx response triggers retries.

Handle duplicate deliveries

Use the notificationId field to deduplicate — webhooks may be retried.

Route by event type

Use the type field to determine how to process each event.

Retries

If your endpoint returns a non-2xx status code or times out, pawaPass will retry delivery using capped exponential backoff with jitter:
  • 55 attempts over approximately 1 week
  • Delay starts at 1 second, doubles each time (1s, 2s, 4s, 8s, …), capped at 4 hours
  • Each delay includes ±25% random jitter to prevent thundering herd
  • If all retries are exhausted, the notification is dropped
Use List verifications or Get verification to poll for missed updates.