Webhooks
Shadowfax sends POST callbacks to your registered URL whenever an order changes state. This is the primary mechanism for receiving real-time updates. Your endpoint must be served over HTTPS.
Payload Format
There is no single payload that every client receives. Your callback body is configured against your account during onboarding: you choose the field names, and each one is bound to a value that Shadowfax supplies. The same pickup event can arrive as {"tracking_id": ...} for one client and {"awb": ...} for another.
This means you should build against the configuration registered for your account rather than against a published example. Your integration POC can give you that configuration. The table below lists the values available to be mapped into it.
| Value | Notes |
|---|---|
awb_number | |
client_order_id | The client_order_id you sent at placement |
client_id | |
status | Display form, e.g. Out For Pickup |
status_id | Code form, e.g. ofp |
remarks | Free text — the reason line for delays, failures and cancellations |
current_location | Hub name, not a pincode |
last_updated | YYYY-MM-DD HH:MM:SS, IST |
last_updated_iso | The same instant as YYYY-MM-DDTHH:MM:SS, IST, with no offset suffix |
created_date, created_time, updated_date, updated_time | Split forms of the same two timestamps |
attempt_number | Pickup attempt counter |
rider_name, rider_contact | Populated on ofp only. rider_contact may be a masked number with a PIN appended rather than a plain number |
otp_verified | Y, N or NA |
pickup_otp | Only if your configuration includes it |
recipient_info | Populated when the item is delivered to the seller or to your warehouse; {} otherwise |
qc_questions | Per-question QC results, sent on picked and qc_failed |
latlong | Coordinates of the pickup or the attempt |
weight_details, image_details | Only if your configuration includes weight capture |
exchange_awb | The paired forward AWB, on exchange orders |
hub_details | Drop-off hub name, address and pincode — self-drop orders only |
Most accounts also receive qc_images as a field of its own, whether or not it was mapped. It holds a list of image URLs and stays empty until the rider's QC images have been uploaded.
Callbacks are registered separately for each return destination, so orders returning to your warehouse and orders returning to a seller can point at different URLs — and enabling one does not enable the other. Staging and production are registered separately as well.
Statuses
A callback can carry any of these status codes:
new, assigned_for_pickup, ofp, picked, qc_failed, recd_at_rev_hub, recd_at_dc, rts_in_process, rts_d, rts_nd, rto_d, rto_nd, cid, nc, na, on_hold, cancelled_by_customer, reopen, lost.
Treat this as an open set and log anything unfamiliar rather than failing on it. Branch on status_id rather than status — the display strings are not stable, and they differ from the ones the tracking API returns for the same state.
Callback Behavior
| Aspect | Detail |
|---|---|
| Method | POST |
| Content-Type | application/json |
| Expected response | 200 OK — note that 201 and 204 are recorded as failures |
| Timeout | 10 seconds |
| Retry on failure | Almost none — see below |
Retries are the one area where reverse callbacks are likely to differ from what you expect. A callback that fails because your endpoint was down, slow, or returned an error is logged and dropped: there is no backoff schedule and no replay queue. Only two narrow cases are retried — a 401 or 500 response triggers a single retry with a refreshed token, and a picked or qc_failed callback is retried once if its QC images aren't ready yet.
Because of this, reconciliation is not optional. Poll tracking on a schedule for your open orders and treat it as the source of truth for anything whose callback never arrived.
Configuration
Register your webhook URL in the SFX 360 Partner Portal. You can configure separate URLs for forward and reverse orders.
Best Practices
- Return
200immediately, process the payload asynchronously. Anything slower than 10 seconds is treated as a failed delivery. - Branch on
status_id, not on the display string. - Implement idempotency — the same event may be delivered more than once.
- Use Tracking as a reconciliation fallback for any missed callbacks.
- Log the raw payload before processing for debugging.