Receive, confirm, and track Same-Day Delivery orders through the Cart API and webhooks.
Early Access (Beta)Same-Day Delivery support for PushCart is in early access. Contact your Locally representative to request access before building against the endpoints and webhooks described here.
Overview
Same-Day Delivery (SDD) lets shoppers buy items that are in stock at a local store and have them delivered to their door the same day by a third-party courier (Uber, Roadie, DoorDash).
SDD orders flow through the same PushCart integration as pickup orders: Locally sends a webhook to your endpoint when the order is placed, you confirm or reject each item via the Cart API, and Locally automatically dispatches a courier once every item has been handled. Delivery progress is then pushed to your webhook endpoint in real time.
This article covers what is different about a delivery order. For the core PushCart workflow — API keys, webhook configuration, and confirming pickup orders — start with PushCart Integration.
Prerequisites
- A working PushCart integration (inventory sync, API key, webhook endpoint). See PushCart Integration.
- The store must have Same-Day Delivery enabled in its Locally dashboard. See Set Up Same Day Delivery.
How a delivery order differs from a pickup order
- The new-order webhook payload includes
for_delivery: 1. - The cart's
typeisDELIVERYinstead ofHOLDorORDER. - Get a Single Cart and Get All Carts responses include a
deliveryobject with the courier, fees, delivery address, tracking link, and live driver info, and populate the cart-leveldelivery_statusfield. - Confirming the order triggers courier dispatch — there is no separate "initiate delivery" call, and you no longer need to pass a
delivery_estimate_idon confirm. - In addition to the item-level webhooks you already receive, Locally sends cart-level delivery status webhooks as the courier picks up and delivers the order.
Lifecycle of a Same-Day Delivery Order
1. Order placed — webhook received
The shopper enters their delivery address at checkout, sees the live courier rate, and completes the order. Their card is authorized but not yet charged.
Locally then POSTs a payload to your webhook endpoint, one per item in the cart, just like a pickup order. Delivery orders are identified by for_delivery: 1:
{
"store_id": 37175,
"upc": "686487455948",
"order_id": "EX2QL6",
"status": "ordered",
"for_ship_to_store": 0,
"for_delivery": 1,
"is_test": 0,
"position_in_cart": 1,
"total_in_cart": 1,
"order_url": "https://www.locally.com/api/v2/cart/EX2QL6"
}The webhook intentionally carries minimal data. Request the order_url (the Get a Single Cart endpoint) to retrieve the full order.
2. Retrieve the order
GET /api/v2/cart/{cart_hash} returns the standard cart payload plus a delivery object that is only present on DELIVERY carts:
{
"properties": {
"type": "DELIVERY",
"hash": "EX2QL6",
"delivery_status": "",
"...": "..."
},
"customer": { "...": "..." },
"store": { "...": "..." },
"items": [ { "...": "..." } ],
"delivery": {
"delivery_type": "SDD",
"carrier_id": 2,
"status": 0,
"carrier_name": "Uber",
"customer_fee": "6.00",
"carrier_fee": "6.00",
"tracking_url": null,
"carrier_tracking_number": null,
"estimated_pickup_at": null,
"estimated_dropoff_at": null,
"actual_pickup_at": null,
"actual_dropoff_at": null,
"signature_url": null,
"dropoff_photo_url": null,
"scheduled_dispatch_at": null,
"delivery_notes": "Gate code is 4482",
"address": {
"first_name": "John",
"last_name": "Doe",
"address_1": "2020 W Willow St",
"address_2": "",
"city": "Chicago",
"state": "IL",
"zip": "60647",
"country": "US"
},
"driver": null
}
}Key fields:
| Field | Description |
|---|---|
delivery.delivery_type | SDD for same-day delivery, CONVENTIONAL for standard shipping carriers. |
delivery.carrier_id | The delivery carrier, named in carrier_name. |
delivery.status | Numeric courier progress code. See Delivery status codes below. |
delivery.customer_fee | The delivery fee the shopper paid at checkout. |
delivery.carrier_fee | The fee charged by the courier. |
delivery.tracking_url | Live tracking link. null until the courier accepts the job. |
delivery.address | The shopper's delivery address. |
delivery.driver | Driver name, vehicle, photo, and live lat/lng once a driver is assigned; null before that. |
delivery.scheduled_dispatch_at | If the store scheduled the courier for later, the dispatch time. |
delivery.signature_url / delivery.dropoff_photo_url | Proof-of-delivery images, when the carrier supports them. |
See Get a Single Cart for a complete delivery-order response.
3. Confirm or reject the items
Confirm each item the same way you confirm a pickup order, via Update a Cart Item:
POST /api/v2/cart/{cart_hash}/{upc}
{
"status": "confirm",
"message": "Confirmed! We will text you when your order is out for delivery."
}Rules specific to delivery orders:
- Confirm in full or reject. Partial-quantity confirmation (
confirmed_qty) is not supported on delivery orders. - Confirming charges the shopper's card, exactly like a BOPIS pickup order.
- No
delivery_estimate_idrequired. Confirming a cart item now auto-triggers delivery creation — Locally uses the estimate captured at checkout, so you do not need to pass adelivery_estimate_idon confirm. - Respond quickly. The standard confirmation window applies, but shoppers expect same-day orders to move fast.
Send the courier now vs. later
By default, the courier is dispatched as soon as the order is fully confirmed. If the order needs prep time before it is ready for pickup — a bike that needs boxing, for example — include scheduled_dispatch_at (UTC, ISO 8601) with your confirmation and the courier will be dispatched at that time instead:
{
"status": "confirm",
"scheduled_dispatch_at": "2026-02-10T19:25:27Z"
}Dispatch — immediate or scheduled — only happens while the store is open.
Expired delivery estimates
Courier quotes expire. If the quote from checkout is no longer valid when you confirm, the API responds with status: false and the message Delivery estimate has expired or is not valid. Orders in this state can still be confirmed from the Locally order management console in the store's Locally dashboard.
Automatic courier dispatch
Once every item in the cart has been confirmed or rejected (with at least one item confirmed), Locally creates the delivery and dispatches the courier automatically. There is no separate "initiate delivery" API call, and no delivery_estimate_id needs to be passed — confirming the item is all that is required. A driver heads to the store, and both the store and the shopper receive notifications at each step.
4. Track the delivery — webhooks
As the delivery progresses, Locally POSTs cart-level delivery webhooks to the same endpoint that receives your order webhooks. Unlike item webhooks, delivery webhooks have no upc — they describe the whole order:
{
"order_id": "EX2QL6",
"delivery_status": "pickup",
"tracking_url": "https://delivery.uber.com/orders/62105936-e413-40d5-aecd-4c335c3cd3c2",
"store_id": 37175,
"for_delivery": 1,
"is_test": 0,
"estimated_dropoff_at": "2026-01-29 16:17:56",
"courier": {
"name": "TEST DRIVER",
"vehicle_description": "Red Toyota Camry",
"photo_url": "https://www.example.com/driver.jpg",
"location": {
"lat": 41.91136867,
"lng": -87.67771437
}
},
"order_url": "https://www.locally.com/api/v2/cart/EX2QL6"
}The delivery_status values you will receive:
delivery_status | Meaning | Additional payload fields |
|---|---|---|
pickup | A courier has accepted the job and is heading to the store. May fire more than once as driver details update; includes the courier object once a driver is assigned. | estimated_dropoff_at, courier |
pickup_complete | The courier has picked up the package from the store. | estimated_dropoff_at |
delivered | The package has been delivered to the shopper. | signature_url, dropoff_photo_url |
canceled | The delivery has been canceled. | — |
Delivery status webhooks are sent for native same-day delivery orders only. DoorDash Marketplace orders receive order and item webhooks but no delivery status webhooks, since DoorDash manages its own fulfillment. See Webhooks.
You can also poll Get a Single Cart at any time — the delivery.status code, delivery.driver location, and the cart-level delivery_status label all update as the delivery progresses.
5. Delivery complete
When the courier marks the delivery complete, the delivered webhook fires with the proof-of-delivery images (where the carrier supports them), and the item status advances to its fulfilled end state (see Cart Item Statuses).
Delivery status codes
The numeric delivery.status field returned by Get a Single Cart:
| Code | Status | Description |
|---|---|---|
0 | Pending | Delivery created; no courier dispatched yet. |
1 | Canceled | The delivery was canceled. |
2 | Pickup | A courier is en route to the store. |
3 | Pickup Complete | The courier has picked up the package. |
4 | Dropoff | The courier is arriving at the shopper's address. |
5 | Delivered | The delivery is complete. |
The cart-level properties.delivery_status field carries a human-readable progress label for the same journey (for example Driver assigned or Delivery to destination complete), and is an empty string before the delivery process starts.
Cancellations and refunds
- Before confirmation — if the shopper cancels or the item is out of stock, reject the item (
"status": "reject") as you would on a pickup order. No charges apply. - After confirmation — the courier is already dispatched. The delivery can only be canceled before the driver arrives at the store, from the Locally order screen. If a delivery is canceled, your webhook endpoint receives a
canceleddelivery webhook. - Item refunds work exactly like pickup orders via the
refundparameter on Update a Cart Item. Note that refunding an item does not cancel a dispatched courier — cancel the delivery too, or the store is still charged for the trip.
For the retailer-facing view of cancellations, returns, and delivery-fee refunds, see Set Up Same Day Delivery.

