Webhooks
Webhooks
Webhooks send a POST notification to your URL whenever an order's status changes. Register your endpoint on the Developers › Webhooks page.
Events
| Event | Description |
|---|---|
order.created | Order was created successfully. |
order.shipping | Package was picked up and is in transit. |
order.delivered | Package was delivered successfully. |
order.problem | A delivery problem occurred (e.g. failed delivery). |
order.returned | Package was returned to the sender. |
order.cancelled | Order was cancelled. |
order.failed | Order failed to process. |
Payload
{
"event": "order.delivered",
"delivery_id": "whd_5c2a",
"created_at": "2026-08-09T11:20:00+07:00",
"data": {
"id": "ord_3a9f",
"resi": "TRK00012345",
"no_order": "INV-20260808-0001",
"status": "delivered",
"courier_code": "ninja",
"courier_service": "Standard",
"charged_amount": 14000,
"is_cod": false,
"cod_amount": 0,
"recipient_name": "Siti Rahma",
"recipient_phone": "08120000000",
"product_name": "Kaos Katun",
"created_at": "2026-08-07T14:03:00+07:00"
}
}
Headers
| Header | Type | Description |
|---|---|---|
X-Kurir-Signature | string | HMAC SHA-256 of {timestamp}.{raw body} using the webhook signing secret. |
X-Kurir-Timestamp | string | Unix timestamp when the webhook was sent. |
X-Kurir-Event | string | Event name, e.g. order.delivered. |
X-Kurir-Delivery | string | Unique webhook delivery ID (for idempotency). |
Verifying Signatures
Recompute the HMAC from the timestamp + raw body and compare it with the header (use a constant-time comparison).
- Node.js
- Python
- PHP
const crypto = require('crypto');
function verify(rawBody, headers, secret) {
const ts = headers['x-kurir-timestamp'];
const expected = crypto
.createHmac('sha256', secret)
.update(`${ts}.${rawBody}`)
.digest('hex');
const got = headers['x-kurir-signature'];
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got));
}
import hmac, hashlib
def verify(raw_body: bytes, headers, secret: str) -> bool:
ts = headers['X-Kurir-Timestamp']
expected = hmac.new(
secret.encode(),
f'{ts}.'.encode() + raw_body,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, headers['X-Kurir-Signature'])
$ts = $_SERVER['HTTP_X_KURIR_TIMESTAMP'];
$raw = file_get_contents('php://input');
$expected = hash_hmac('sha256', $ts . '.' . $raw, $secret);
$ok = hash_equals($expected, $_SERVER['HTTP_X_KURIR_SIGNATURE']);
Retries & Auto-Disable
- Respond with
2xxas quickly as possible to mark the webhook as received. - Non-
2xxresponses or timeouts are retried with incremental backoff. - Endpoints that keep failing may be disabled automatically; re-enable them on the Webhooks page.
- Use
X-Kurir-Deliveryas an idempotency key so you don't process duplicate events.
info
Manage URLs and secrets, and view delivery history, in Developers › Webhooks.
Was this page helpful?