Skip to content

Webhooks

Webhooks let Wasal push order events to your server in real time, so you don't need to poll.

How it works

  1. Register an HTTPS endpoint URL.
  2. When a matching event occurs, Wasal sends a POST request to your URL with a signed JSON payload.
  3. Respond with any 2xx status within 8 seconds to acknowledge delivery.

Payload format

Every webhook request has this shape:

json
{
  "event": "order.status_changed",
  "timestamp": "2025-06-01T10:30:00.000Z",
  "data": { /* event-specific payload */ }
}

Headers sent on every request:

HeaderValue
Content-Typeapplication/json
X-Wasal-EventEvent name (e.g. order.status_changed)
X-Wasal-Signaturesha256=<hmac-hex>

Verifying the signature

Compute HMAC-SHA256 of the raw request body using your webhook's secret, then compare with the X-Wasal-Signature header.

js
const crypto = require('crypto');

function isValidSignature(rawBody, secret, signatureHeader) {
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signatureHeader),
    Buffer.from(expected)
  );
}

Always use timingSafeEqual to prevent timing attacks. Reject any request where the signature doesn't match.


Available events

EventTriggered when
order.createdA new order is placed.
order.status_changedAn order's status changes (e.g. pendingassigned).
order.deliveredAn order is delivered.
order.cancelledAn order is cancelled.

If you register a webhook without specifying events, all four events are subscribed by default.


Register a webhook

POST /integration/merchant/webhook

json
{
  "url": "https://yourstore.com/api/wasal-webhook",
  "events": ["order.created", "order.status_changed"]
}
FieldRequiredNotes
urlYesMust start with https://.
eventsNoArray of event names. Omit to subscribe to all events.

Response: 201 Created

json
{
  "success": true,
  "data": {
    "webhook": {
      "_id": "665f...",
      "url": "https://yourstore.com/api/wasal-webhook",
      "events": ["order.created", "order.status_changed"],
      "active": true,
      "secret": "a3f8b2...",
      "createdAt": "2025-06-01T10:00:00.000Z"
    }
  }
}

Save the secret. It is shown only once at creation. You will need it to verify incoming requests.


List webhooks

GET /integration/merchant/webhook

Returns all registered webhooks for your merchant. The secret is not included in list or get responses.


Update a webhook

PUT /integration/merchant/webhook/:webhookId

Updates the URL, events, or active state. Only send the fields you want to change.

json
{
  "url": "https://yourstore.com/api/wasal-v2",
  "events": ["order.delivered"],
  "active": false
}

Response: 200 OK — updated webhook object (without secret).


Delete a webhook

DELETE /integration/merchant/webhook/:webhookId

Removes the webhook. Deliveries in flight will still complete.


Send a test ping

POST /integration/merchant/webhook/:webhookId/test

Sends a test ping event to the registered URL. Useful to verify your endpoint is reachable and your signature verification logic is correct.

Test payload delivered to your URL:

json
{
  "event": "ping",
  "timestamp": "2025-06-01T10:30:00.000Z",
  "data": { "message": "This is a test ping from Wasal" }
}

Returns 200 if your endpoint responded with a 2xx, or 502 if it was unreachable.


Errors

HTTPcodeMeaning
400VALIDATION_FAILEDurl missing or not https://, or invalid event names — see errors.
404WEBHOOK_NOT_FOUNDWebhook does not exist or is not owned by your merchant.

Wasal Delivery Platform · Integration API v1.0.0