Webhook Reference
Summary
Register an HTTPS endpoint so Elim calls into your system whenever an order or its payment changes state — instead of polling for status. This page covers the events, management endpoints, payload structure, signature verification and retry policy.
For where webhooks fit in the order lifecycle, see the Order guide and the Order API reference.
Every endpoint requires JWT auth (Authorization: Bearer <token>) or an API Key (x-api-key).
Events
| Event | Sent when |
|---|---|
order.updated | The order’s status changes: platform sync, scheduled sync, or cancellation |
payment.updated | The payment_status changes: payment requested, request cancelled, approved, rejected, platform payment success/failure, or refund |
You only receive events you subscribe to. Usually subscribe to both.
Subscription endpoints
Prefix /v1/webhooks.
| Endpoint | Method | Description |
|---|---|---|
/v1/webhooks | GET | List existing subscriptions |
/v1/webhooks | POST | Create a subscription — returns secret once |
/v1/webhooks/:id | PATCH | Update url, events, or is_active |
/v1/webhooks/:id | DELETE | Delete the subscription |
/v1/webhooks/:id/rotate-secret | POST | Rotate secret — returns the new value once |
/v1/webhooks/:id/deliveries | GET | Recent delivery logs |
/v1/webhooks/:id/test | POST | Send a test delivery to the registered url |
Create body
{
"url": "https://your-system.example/webhooks/elim",
"events": ["order.updated", "payment.updated"],
"is_active": true
}
secret is returned only right after create or rotate-secret. Store it securely — you need it to verify every request. If you lose the secret, call rotate-secret to reissue it (the old signature stops being valid).
Payload structure
Both events share one shape — they differ only in the event field:
{
"id": "evt_4a1f2c...",
"event": "payment.updated",
"created_at": "2026-06-19T00:00:00.000Z",
"data": {
"order": {
"id": "ORD0000000123",
"platform": "taobao",
"order_id": "123456789",
"status": "paid",
"payment_status": "paid",
"platform_payment_status": "success",
"total_amount_cny": 123.45,
"updated_at": "2026-06-19T00:00:00.000Z"
}
}
}
| Field | Description |
|---|---|
id | Event id, evt_... — use it to de-duplicate |
event | order.updated or payment.updated |
created_at | When the event was generated (ISO 8601) |
data.order.id | Internal order id ORD... — the key to look the order up in your system |
data.order.order_id | Platform order id (may be null if not yet created on the platform) |
data.order.status | Platform status — see the status table |
data.order.payment_status | Elim payment status — see the payment_status table |
data.order.platform_payment_status | Payment result on the platform side |
data.order.total_amount_cny | Order amount (CNY), may be null |
data.order.updated_at | The order’s last update (ISO 8601) |
Your handler: look up data.order.id, update the order’s state in your system, then return HTTP 2xx. Payloads may arrive out of order — always trust the newer updated_at and ignore an event older than the state you already hold.
Headers on each delivery
| Header | Value |
|---|---|
Content-Type | application/json |
User-Agent | elim-api-webhooks/1.0 |
X-Elim-Event | Event name |
X-Elim-Delivery | Delivery id (changes per retry) |
X-Elim-Timestamp | Unix time in seconds |
X-Elim-Signature | sha256=<hmac> |
Signature verification
Signing string: "{X-Elim-Timestamp}.{raw_json_body}" — use the raw body as received, do not parse and re-serialize it.
Algorithm: HMAC-SHA256(secret, signing_string), compared against the part after sha256= in X-Elim-Signature using a timing-safe comparison.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyElimWebhook(
secret: string,
timestamp: string,
rawBody: string,
signature: string,
): boolean {
const expected = `sha256=${createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex')}`;
return timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
Reject requests whose X-Elim-Timestamp is too far from now (e.g. more than 5 minutes) to limit replay.
Retry policy
| Condition | Result |
|---|---|
2xx response | Marked delivered |
Timeout / network error / non-2xx | Retry scheduled |
| Total attempts | 3 |
| Delays between attempts | 60 seconds, then 300 seconds |
| Per-request timeout | 10 seconds |
Check per-delivery results at GET /v1/webhooks/:id/deliveries. Use POST /v1/webhooks/:id/test to quickly validate your receiving setup.
Security
- Production URLs must be HTTPS. Dev may use
localhost. - Private / internal / metadata IPs are blocked in production.
secretis shown only after create orrotate-secret.- Payloads never contain passwords, API keys, JWTs, or platform access tokens.
If you have not set up webhooks
Query status directly anytime with GET /v1/orders/:id — on each call Elim syncs the latest status from the platform before responding. See the Order API reference.