Status mapping
Your platform has its own delivery statuses, so you need a table from Reeds' statuses to yours. Build it once, and drive it from webhooks.
Example: an aggregator
An aggregator with six statuses of its own might map Reeds' statuses like this.
| Reeds status | Aggregator status |
|---|---|
requires_action | pending |
scheduled, rider_assigned | confirmed |
picked_up | picked_up |
at_hub, in_transit, out_for_delivery, failed_attempt, on_hold | in_transit |
delivered | completed |
cancelled | cancelled |
Reeds' full list is on Delivery statuses.
Which webhooks to listen to
| Event | Use it to |
|---|---|
delivery.status_changed | Update your own status. It carries previous_status and the full delivery. |
delivery.booked | Confirm the booking and store the tracking_code and tracking_url. |
delivery.schedule_changed | Update the delivery date you show. |
delivery.cancelled | Mark the order cancelled and handle the refund on your side. Includes the cancellation block. |
delivery.requires_action, delivery.expiring | Alert your ops team when a draft needs attention. |
Verify the signature on every request. Events can arrive more than once, and out of order: skip ids you have already processed, and compare data.delivery.updated_at against what you hold, or fetch the delivery with GET /deliveries/{id}.
Mapping in code
const MAP = {
requires_action: 'pending',
scheduled: 'confirmed',
rider_assigned: 'confirmed',
picked_up: 'picked_up',
at_hub: 'in_transit',
in_transit: 'in_transit',
out_for_delivery: 'in_transit',
failed_attempt: 'in_transit',
on_hold: 'in_transit',
delivered: 'completed',
cancelled: 'cancelled',
};
// Unknown statuses: keep the last known status instead of failing.
const mapStatus = (reeds, current) => MAP[reeds] ?? current;
Unknown statuses
Reeds may add statuses later. When one arrives that you don't know, keep your current status, log it, and don't reject the webhook with an error: a non-2xx reply makes Reeds retry it.