Payment Webhooks

Receive real-time payment event notifications with HMAC-signed delivery

🔔 Payment Webhooks

Register webhook endpoints to receive real-time notifications when payments are completed, failed, refunded, or when subscriptions change.


Register a Webhook

POST /api/v1/webhooks
FieldTypeRequiredDescription
urlstringYesHTTPS endpoint to receive events
eventsarrayNoEvent types to subscribe to (omit for all)
curl -X POST /api/v1/webhooks \
  -H "X-Client-ID: $CLIENT_ID" \
  -H "X-Client-Secret: $CLIENT_SECRET" \
  -d '{
    "url": "https://yourplatform.com/webhooks/audit1",
    "events": ["payment.completed", "payment.failed", "payment.refunded"]
  }'
{
  "ok": true,
  "data": {
    "id": "685abc123def456789012345",
    "url": "https://yourplatform.com/webhooks/audit1",
    "secret": "whsec_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
    "events": ["payment.completed", "payment.failed", "payment.refunded"],
    "status": "active"
  }
}
⚠️

Save the secret immediately — it's only shown once. You'll use it to verify webhook signatures.


Event Types

EventTrigger
payment.completedPayment received (card or bank debit)
payment.failedPayment attempt failed
payment.refundedRefund processed
subscription.createdNew recurring subscription started
subscription.cancelledSubscription cancelled
installment.paidInstallment payment received
installment.failedInstallment payment failed

Webhook Payload

Each delivery includes these headers:

HeaderDescription
X-Webhook-SignatureHMAC-SHA256 signature
X-Webhook-TimestampUnix timestamp in milliseconds
X-Webhook-EventEvent type (e.g., payment.completed)
X-Webhook-IDUnique event ID

Example payload body:

{
  "event_type": "payment.completed",
  "payment_id": "686abc123def456789012345",
  "employer_id": "681xyz789abc123456789012",
  "carrier_id": "680abc456def789012345678",
  "policy_id": "682def789ghi012345678901",
  "amount_cents": 150000,
  "payment_type": "down_payment",
  "completed_at": "2026-04-14T15:30:00.000Z"
}

Verifying Signatures

Always verify the X-Webhook-Signature to confirm the event came from Audit1 and wasn't tampered with.

Verification Steps

  1. Extract X-Webhook-Signature and X-Webhook-Timestamp from headers
  2. Construct the signed payload: ${timestamp}.${raw_body}
  3. Compute HMAC-SHA256 using your webhook secret
  4. Compare signatures (use constant-time comparison)

JavaScript

const crypto = require("crypto");

function verifyWebhook(secret, signature, timestamp, body) {
  const payload = `${timestamp}.${body}`;
  const expected = crypto
    .createHmac("sha256", secret)
    .update(payload)
    .digest("hex");

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

// In your webhook handler:
app.post("/webhooks/audit1", (req, res) => {
  const sig = req.headers["x-webhook-signature"];
  const ts = req.headers["x-webhook-timestamp"];

  if (!verifyWebhook(WEBHOOK_SECRET, sig, ts, req.rawBody)) {
    return res.status(401).send("Invalid signature");
  }

  // Process the event
  const event = req.body;
  console.log(`Received ${event.event_type}`);
  res.status(200).send("OK");
});

Python

import hmac, hashlib

def verify_webhook(secret, signature, timestamp, body):
    payload = f"{timestamp}.{body}"
    expected = hmac.new(
        secret.encode(), payload.encode(), hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(expected, signature)

Retry Policy

If your endpoint doesn't respond with 2xx within 10 seconds, we retry with exponential backoff:

AttemptDelay
1Immediate
21 second
35 seconds
425 seconds
5~2 minutes

After 5 consecutive failures per event, we stop retrying that event.

After 10 consecutive failures across all events, the webhook subscription is automatically disabled. Re-enable it by deleting and re-registering.


Manage Webhooks

List Webhooks

GET /api/v1/webhooks

Delete a Webhook

DELETE /api/v1/webhooks/{id}

Best Practices

✅ Do❌ Don't
Respond with 200 quickly, process asyncBlock the response while doing heavy processing
Verify the HMAC signature on every eventTrust events without signature verification
Handle duplicate events idempotentlyAssume each event is delivered exactly once
Use HTTPS endpoints onlyUse HTTP (we reject non-HTTPS URLs)
Log the X-Webhook-ID for debuggingIgnore event IDs