Carrier webhooks
Carriers push delivery updates to Wocart. The server verifies the signature, stores the events in an inbox, answers the carrier immediately, and processes the events after the response. Your integration reads the resulting shipment state through the API.
To receive your own store's events on your server, read Webhooks instead.
Inbound webhooks exist for Yalidine and ZR Express. NOEST, the EcoTrack-platform companies and Guepex send none: their shipments are synced every five minutes, and on demand with POST /shipments/{id}/sync or POST /delivery-companies/{id}/sync-shipments.
Endpoints
| Carrier | Endpoint | Delivery shape | Signature |
|---|---|---|---|
| Yalidine | POST /webhooks/yalidine | A batch of events of one type | HMAC-SHA256 in x-yalidine-signature |
| Yalidine | GET /webhooks/yalidine | CRC challenge | Echoes crc_token as plain text |
| ZR Express | POST /webhooks/zr_express | One Svix event per request | Svix HMAC-SHA256 |
The paths are the URLs the carriers hold. Do not put them behind auth: the carriers cannot send your API key. The signature is the authentication.
How intake works
-
Carrier to Wocart
The carrier sends a signed
POSTto/webhooks/yalidineor/webhooks/zr_express. -
Verify and split
Wocart checks the signature against the company's secret and splits the carrier envelope into individual events.
-
Store in the inbox
Each event goes into
webhook_events, keyed by its provider event ID. -
Answer the carrier
Wocart returns
200 {"received":true}without waiting for processing. -
Process after the response
A few seconds later the events queue wakes the drain, which applies each event's shipment milestones and records their Business Events. The five-minute schedule runs the same drain, so an event a lost wake missed is still processed.
The carrier gets its 200 as soon as the events are stored. Processing failures do not fail the webhook; the drain retries them on the inbox's schedule. Yalidine requires an answer within 10 seconds and retries a failed delivery seven times over 40 hours, so this split matters.
Set up a webhook
Both flows start on the delivery company's credentials page in the dashboard.
Yalidine
- Open the company's credentials page and copy the receiver URL from the webhook setup card.
- In Yalidine's Webhooks Dashboard, create an endpoint with that URL.
- Subscribe to the event types you need. Yalidine validates the URL with the CRC challenge.
- Copy the signing secret from Yalidine back into the card and save it. Store the same value in your secret manager.
ZR Express
- Open the company's credentials page and choose Register webhook.
- The server registers the endpoint with ZR Express and fetches the signing secret for you.
- The card shows the endpoint as registered. Use Unregister to remove it.
Send a test event from the carrier and confirm the delivery company receives it.
A webhook needs its secret. A delivery no company's secret verifies is refused with 401 and never stored: what a carrier reports becomes a Business Event that merchants' systems and customers may be told about, so it must be proven to come from the carrier. If ZR Express does not give its signing secret, the registration is undone and nothing is kept; register again.
Signature verification
Yalidine
Yalidine signs the raw request body with HMAC-SHA256 using the company's webhook secret. The signature arrives in x-yalidine-signature (or x_yalidine_signature). The server accepts lowercase hex, uppercase hex and base64 representations, and compares in constant time.
The GET challenge is separate: when Yalidine sends subscribe and crc_token query parameters, the server echoes the token as plain text. This lets Yalidine verify the URL before it starts sending events.
ZR Express
ZR Express uses Svix. The signed content is:
Code
The signature arrives in svix-signature, and the server accepts any of the space-separated v1,<base64> entries. A missing svix-id, svix-timestamp or svix-signature is rejected.
Idempotency and ordering
- Yalidine batches many events in one request. Each event has its own
event_id, which is the inbox key. - ZR Express sends one event per request.
svix-idis the inbox key. - Duplicate deliveries are ignored by the inbox, so a carrier retry cannot apply the same event twice.
- Events can arrive out of order. The server applies shipment milestones by their event timestamp, not by arrival order.
Local development
Carriers need a public HTTPS URL. Expose your local Worker with a tunnel you trust, then configure that origin with the carrier. For Yalidine, create the endpoint at <tunnel-origin>/webhooks/yalidine and save its secret in the company's webhook card. For ZR Express, send the tunnel origin as X-Worker-URL when you register, so the endpoint it creates points at the tunnel instead of localhost.
The local receiver is still http://localhost:8787/webhooks/yalidine or /webhooks/zr_express, so you can replay a signed payload with curl while developing:
Code
Related
- Shipments in the API reference
- Errors for the delivery failure envelope
- Delivery companies for provider configuration and sync