WiPay
Webhooks

Overview

Real-time event notifications for WAPI and Payments API.

WiPay delivers server-to-server event notifications to HTTPS endpoints you register for your merchant account. A single endpoint receives events for one API family; register a separate endpoint per family if you consume both.

API familyEvent prefixReference
payments_apipayment.*Payments API events
wapiwithdrawal.*WAPI events

Delivery model

  • Method: POST with Content-Type: application/json and Accept: application/json.
  • Body: a JSON envelope (see below) sent as the raw request body.
  • Acknowledge with any 2xx HTTP response as soon as you have durably accepted the event.
  • Any non-2xx, connection error, or timeout is treated as a delivery failure and scheduled for retry.
  • The same delivery identifier is reused across retries; always treat the id field (and the X-WiPay-Webhook-Id header) as an idempotency key.

Headers

Every request carries:

HeaderPurpose
X-WiPay-Webhook-EventEvent type (e.g. payment.success).
X-WiPay-Webhook-IdUnique UUID for this event. Reused across retries.
X-WiPay-Webhook-Signaturesha256=<hex> HMAC of the raw request body.
X-WiPay-Webhook-TimestampUnix timestamp (seconds, UTC) when the request was signed.
X-WiPay-Webhook-VersionSignature scheme version (currently v1).

Envelope

{
  "id": "3e1f9b2c-...-...-4a1e",
  "api_family": "payments_api",
  "event": "payment.success",
  "occurred_at": "2026-04-17T15:04:03+00:00",
  "data": { /* event-specific payload */ },
  "meta": { /* event-specific context; may be empty */ }
}

id is the same value as X-WiPay-Webhook-Id. data and meta keys vary by event; consumers must be forward-compatible and ignore unknown keys.

Signature verification

  1. Read the raw request body exactly as received (do not reformat).
  2. Compute HMAC-SHA256(body, endpointSecret) using the signing secret shown once when you created or rotated the endpoint.
  3. Compare against the hex portion of X-WiPay-Webhook-Signature using a constant-time comparison.
  4. Reject requests with a missing, malformed, or mismatched signature.

Replay protection

X-WiPay-Webhook-Timestamp is the signing time. Reject requests older than your tolerance window (five minutes is recommended) to mitigate replay.

Example (Node.js)

const crypto = require('crypto');

function verify(req, secret) {
    const raw = req.rawBody; // Express: use express.raw({ type: 'application/json' })
    const header = req.header('X-WiPay-Webhook-Signature') || '';
    const [, received] = header.split('=');

  if (!received || received.length !== 64) {
    return false;
  }

    const expected = crypto
        .createHmac('sha256', secret)
        .update(raw)
        .digest('hex');

    return received && crypto.timingSafeEqual(
        Buffer.from(expected, 'hex'),
        Buffer.from(received, 'hex')
    );
}

Example (PHP)

$raw = file_get_contents('php://input');
$header = $_SERVER['HTTP_X_WIPAY_WEBHOOK_SIGNATURE'] ?? '';
[, $received] = array_pad(explode('=', $header, 2), 2, '');
$expected = hash_hmac('sha256', $raw, $endpointSecret);

if (!hash_equals($expected, $received)) {
    http_response_code(400);
    exit;
}

Delivery retries

  • WiPay retries failed deliveries automatically when your endpoint returns a non-2xx, times out, or cannot be reached.
  • Retries use backoff over a limited delivery window rather than a tight loop.
  • Base retry cadence:
Retry #Nominal delay
11 minute
22 minutes
35 minutes
410 minutes
515 minutes
630 minutes
71 hour
82 hours
94 hours
108 hours
11 and later8 hours
  • Actual retry timing can vary slightly, and retries stop once the delivery window closes.
  • Repeated failures may cause WiPay to disable an endpoint until you review and re-enable it in the Developer page.
  • A retry is a redelivery of the same logical event, so X-WiPay-Webhook-Id remains stable across retry attempts.

Idempotency

  • X-WiPay-Webhook-Id (and the envelope id) is stable across retries for a given logical event. Use it as the primary idempotency key in your handler.
  • Ignore events you have already processed. A delivered event may be observed more than once if your handler took longer than the timeout.

Managing endpoints

Register, rotate the secret, and inspect delivery history from the Developer page inside the WiPay dashboard. Endpoint URLs must use public HTTPS, must not contain embedded credentials, and must resolve to public internet-routable IP addresses. The signing secret is displayed only once at creation or rotation; store it in a secure secret manager.

If you send a test from the Developer page, WiPay delivers a webhook.test event. Handle or ignore that event separately from your production workflows.