Inbound webhook
The inbound webhook refreshes an order record immediately when your site says “this order changed”, so the assistant tells customers the latest status. The setting is on Settings → Inbound webhook.
- Create secret. The secret (
whsec_…) is shown once. If you rotate it, the old one stops working immediately. There is one secret per company; both sources use it. - Use one of the addresses shown on the page:
- WooCommerce:
https://<your-console-host>/hooks/<company>/woocommerce - Your own system:
https://<your-console-host>/hooks/<company>/generic
- WooCommerce:
In WordPress go to WooCommerce → Settings → Advanced → Webhooks → Add webhook:
| Field | Value |
|---|---|
| Topic | Order updated (and another webhook for: Order created). Optional, for instant prices: Product updated, Product created, Product deleted |
| Delivery URL | …/hooks/<company>/woocommerce |
| Secret | The secret from Zitena |
| API version | WP REST API v3 |
- The signature is verified with
X-WC-Webhook-Signature(base64 HMAC-SHA256 of the body). - The
order.created,order.updatedandorder.restoredtopics and the product topics (product.created,product.updated,product.deleted,product.restored,product.published) are processed; other topics are ignored with{"ok": true, "ignored": "<topic>"}. - For product topics the body is not trusted: the product is re-read from the store and updated in the catalog right away. A product the store no longer has becomes inactive.
- The order body is written to the record directly; if it can’t be parsed, the order is re-read from the store with a single request.
- The unsigned ping WooCommerce sends when you save a webhook has no effect.
The body uses the same order format as the Data API (ApiOrder):
{"id": "evt-0001", "event": "order.updated", "order": {"external_id": "98765", "status": "shipped", "created_at": "2026-09-24T10:15:00+03:00", "modified_at": "2026-09-24T15:00:00+03:00", "carrier": "Örnek Kargo", "tracking_number": "123456789012"}}For several orders send "orders": [ … ] (up to 1000). id is the delivery id (otherwise the X-Zitena-Delivery header is used).
The signature uses the same scheme as outbound webhooks:
X-Zitena-Signature: t=<unix saniye>,v1=<hex(HMAC-SHA256(gizli, "<t>.<ham gövde>"))>SECRET=whsec_xxxBODY='{"id": "evt-0001", "event": "order.updated", "order": {"external_id": "98765", "status": "shipped", "created_at": "2026-09-24T10:15:00+03:00", "modified_at": "2026-09-24T15:00:00+03:00"}}'TS=$(date +%s)SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //')curl -s -X POST "$RZ_API/hooks/firma/generic" -H "Content-Type: application/json" \ -H "X-Zitena-Signature: t=$TS,v1=$SIG" -d "$BODY"# {"ok": true, "orders": 1, "inserted": 0, "updated": 1, "unchanged": 0}import crypto from 'node:crypto';const body = JSON.stringify({ id: `evt-${orderId}-${modifiedAt}`, event: 'order.updated', order });const t = Math.floor(Date.now() / 1000);const v1 = crypto.createHmac('sha256', process.env.RZ_INBOUND_SECRET).update(`${t}.${body}`).digest('hex');await fetch(`${process.env.RZ_API}/hooks/firma/generic`, { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-Zitena-Signature': `t=${t},v1=${v1}` }, body,});Responses
Section titled “Responses”| Status | Body | Meaning |
|---|---|---|
| 200 | {"ok": true, "orders": 1, "inserted": 0, "updated": 1, "unchanged": 0} | Processed |
| 200 | {"ok": true, "duplicate": true} | The same delivery id was already processed within 24 hours |
| 401 | invalid_signature | Wrong signature or timestamp outside ±300 s |
| 404 | not_found | Company, source or secret not configured (the company’s existence is not revealed) |
| 413 | payload_too_large | Body larger than 5 MB |
| 422 | invalid_json, invalid_order or a field list | Invalid body |
| 503 | store_unavailable | The WooCommerce body couldn’t be parsed and the store couldn’t be reached |
The same delivery id is not processed twice within 24 hours: resending is safe. A delivery id is only recorded after the signature is verified, so a forged request can’t block a real delivery. The secret and order contents are never logged.
© 2026 Erusoft