Appearance
Webhooks
Webhooks let Wasal push order events to your server in real time, so you don't need to poll.
How it works
- Register an HTTPS endpoint URL.
- When a matching event occurs, Wasal sends a
POSTrequest to your URL with a signed JSON payload. - Respond with any
2xxstatus 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:
| Header | Value |
|---|---|
Content-Type | application/json |
X-Wasal-Event | Event name (e.g. order.status_changed) |
X-Wasal-Signature | sha256=<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
timingSafeEqualto prevent timing attacks. Reject any request where the signature doesn't match.
Available events
| Event | Triggered when |
|---|---|
order.created | A new order is placed. |
order.status_changed | An order's status changes (e.g. pending → assigned). |
order.delivered | An order is delivered. |
order.cancelled | An 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"]
}| Field | Required | Notes |
|---|---|---|
url | Yes | Must start with https://. |
events | No | Array 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
| HTTP | code | Meaning |
|---|---|---|
| 400 | VALIDATION_FAILED | url missing or not https://, or invalid event names — see errors. |
| 404 | WEBHOOK_NOT_FOUND | Webhook does not exist or is not owned by your merchant. |
