Partner API: sending orders and receiving callbacks
Order submission (inbound HMAC in hex), order.created and order.status_changed callbacks (outbound HMAC sha256=), reconciliation endpoints, dedupe by X-N1-Delivery-Id, retries and circuit breaker auto-recovery.
In this guide you will…
- Build the base URL and the
POST /api/webhooks/partner/ordersendpoint - Sign inbound requests (partner → N1) in hex, with no prefix
- Validate outbound callbacks (N1 → partner) using
sha256=in the header - Interpret response codes and the
PARTNER-{identifier}-{external_order_id}ID
Base URLs
Every route uses the same host as your N1 instance (where the panel is hosted). For example:
https://YOUR-N1-DOMAIN.com/api/webhooks/partner/ordershttps://YOUR-N1-DOMAIN.com/api/webhooks/partner/docshttps://YOUR-N1-DOMAIN.com/api/webhooks/partner/health
Replace YOUR-N1-DOMAIN.com with the real domain.
Inbound — sending orders (POST /api/webhooks/partner/orders)
Required headers
Content-Type: application/jsonX-API-Key: key in thepk_live_orpk_test_format (the one shown when you created the API Key)X-Webhook-Timestamp: Unix time in seconds (integer)X-Webhook-Signature: HMAC-SHA256 signature in hex ( without thesha256=prefix )
How to compute the signature (inbound)
- Signed string:
timestamp + "." + raw JSON body— the dot is literal, and the body must be exactly the bytes sent in the request (same key order, spaces and line breaks as sent) HMAC-SHA256(signed_string, webhook_secret)→ output in hexadecimal- Send that hex value in
X-Webhook-Signature
signature = HMAC_SHA256_hex( timestamp + "." + rawBody, webhook_secret )Time window
X-Webhook-Timestamp must be within roughly 5 minutes of the server clock (anti-replay). Timestamps outside the window produce a signature/timestamp error.
Responses and errors
- 201: order created successfully (the body includes
order_id) - 400: invalid payload (Zod schema) — fix the fields listed in
details - 401: invalid/inactive API Key or invalid HMAC signature or missing/invalid timestamp — check the secret, the signed string and
X-Webhook-Timestamp - 403: IP not allowed — when an IP whitelist is configured for that key (adjust via administrator/API/support; there is no screen for this in the API Keys panel)
- 409: duplicate order — same
external_order_idfor the same partner identifier - 429: rate limit — wait and retry (the response carries a
retry_afterheader in seconds)
The order ID in N1
The internal ID generated is:
PARTNER-{partnerIdentifier}-{external_order_id}
Use the same external_order_id you sent in the JSON to correlate with the source system.
Outbound — callbacks (N1 → your endpoint)
When an order is created or changes status, N1 can POST to your callbackUrl (if configured). The full documentation with validation examples lives at GET /api/webhooks/partner/docs and in the integration prompt (button in the API Keys panel).
Events
order.created: fired immediately after a successful creation (useful as an auditable record beyond the HTTP 201 response). Requires"created"in the API key'scallback_events.order.status_changed: fired on any order status change, from any source (internal ops, carrier, 17TRACK, syncs).
The X-N1-Event header tells you which event was delivered.
Headers + signature
X-N1-Signature:sha256=+ hex (different from inbound, which is hex only)X-N1-Timestamp: Unix time in seconds. Your validation must reject anything outside the 5-minute window.X-N1-Event:order.createdororder.status_changedX-N1-Delivery-Id: unique UUID — your code MUST deduplicate on this value (TTL ≥ 30 days). The same delivery can arrive more than once (retries, manual replay).- Signed payload:
timestamp + "." + rawBody.
Retries, dead-letter and circuit breaker
- Your endpoint must answer 2xx. Any other status (or a network error) triggers a retry: 3 attempts with
1min → 5minbackoff → dead-letter. - Circuit breaker (auto-recovery): after 10 consecutive failures, N1 stops sending for 30 minutes. If it still fails when reopening, the wait doubles: 60 min → 120 min → … capped at 24 h. Any 2xx response resets it. No manual action is required (the reactivation button in the panel is only an override).
Reconciliation (partner auto-recovery)
If your endpoint went down or you missed callbacks, three GET/POST endpoints let you recover without asking for manual help. They require the same 6 security layers as the creation POST; for GET, the signed string is timestamp + "." + URL-path-with-query-string.
GET /api/webhooks/partner/orders/:external_order_id— current state of one order.GET /api/webhooks/partner/orders?updated_since=ISO&limit=100&offset=0— list orders changed after the timestamp (paginated).POST /api/webhooks/partner/orders/:external_order_id/replay-callbacks— re-queues the last N callbacks for that order (body:{ "limit": 5 }, default 5, max 20).
Full examples at /api/webhooks/partner/docs and in the panel's LLM prompt.
Service health
GET /api/webhooks/partner/health — public response { "status": "ok", ... } for monitoring. No authentication required.
Limits and the panel
Rate limiting and IP whitelisting exist in the API; if they do not appear in your panel, treat them as adjustable via administrator or support. Do not assume buttons that are not in the interface.
Related article
Panel setup (creating a key, secret, callback): Partner API Keys — panel.