Direct Delivery
Direct Delivery API
The Direct Delivery API enables retailers and DSP aggregators to request autonomous delivery quotes, create autonomous deliveries from those quotes, and receive real-time status updates via webhooks.
The flow is two-step: quote first, then create. A quote returns availability, pickup ETA, delivery ETA, and locked delivery cost; the create call promotes that quote into an active delivery, honoring the same locked terms.
Authentication
All requests require an Autolane API key in the Authorization header and a per-site x-retailer-id header. Your organization and retailer context are resolved automatically from these.
Permissions
API keys carry granular permissions:
Create API keys in the Autolane Portal under Integrations > API Keys. Toggle dev mode in the portal to switch between production and sandbox keys; the dev-mode badge confirms which environment your new key targets. See Authentication for the full walk-through.
Request fields
external_delivery_id
A retailer-provided string (1 to 255 characters) that uniquely identifies the delivery in your own system. Scoped per-retailer: two different retailers can use the same external_delivery_id without collision.
The same value is also the idempotency key for the create call. Re-POSTing POST /dd/v1/deliveries with an external_delivery_id whose quote was already consumed returns 409 QUOTE_ALREADY_CONSUMED (see Idempotency below).
customer.phone
A phone number in strict E.164 format: a leading +, then 7 to 15 digits, with the first digit between 1 and 9.
delivery_address
Required fields: street, city, state, zip. Optional unit and location ({ lat, lng }). Provide location to skip server-side geocoding; omit it and the API geocodes the address. A GEOCODE_FAILED response (422) means geocoding came back empty.
ready_by
ISO 8601 timestamp for when the order will be ready at the store. Must be in the future relative to server clock. Failures return 400 INVALID_READY_BY.
order_items
An array of up to 50 items. Each item is a JSON object with no required fields and a 4096-byte stringified-JSON cap per item.
In v1 the field is free-form to support a wide range of retailer SKU shapes. We strongly recommend including at least:
A future API version will enforce these as required fields; integrations that ship them now will not need to change.
Delivery Lifecycle
One status vocabulary
A delivery’s status speaks a single vocabulary everywhere it appears — the response to POST /dd/v1/deliveries, the top-level status on GET /dd/v1/deliveries and GET /dd/v1/deliveries/{external_delivery_id}, the list endpoint’s ?status= filter, and the status carried by pickup_status.changed webhooks.
Values: SCHEDULED, ASSIGNED, EN_ROUTE_TO_STORE, ARRIVED_AT_STORE, WAITING_FOR_LOAD, LOADED, EN_ROUTE_TO_CUSTOMER, ARRIVED_AT_CUSTOMER, COMPLETED, FAILED, CANCELLED, EXPIRED.
- A newly created delivery returns
status: "SCHEDULED". EXPIREDis a terminal status for deliveries that were never dispatched beforeready_byplus the grace period; it never appears in webhooks (no dispatch ever happened).- The nested
pickup.statusfield on GET/list responses carries the same value as the top-levelstatusand is retained for response-shape stability — read the top-level field.
The diagram above traces the full lifecycle.
Quote Semantics
- A quote is identified by
(retailer, external_delivery_id). Re-quoting with the same key replaces the prior quote. - A quote is valid for 5 minutes. After
expires_at, callingPOST /dd/v1/deliveriesreturns410 QUOTE_EXPIRED. - A quote can only be consumed once. After a successful create, re-creating with the same
external_delivery_idreturns409 QUOTE_ALREADY_CONSUMED. - A quote with
available: falsecannot be promoted to a delivery. Calling create returns422 QUOTE_NOT_AVAILABLE.
Cancellation
Cancel a delivery via PATCH /dd/v1/deliveries/{external_delivery_id} with { "status": "CANCELLED" }. Cancellation is allowed while the delivery is in the pre-load window (SCHEDULED through WAITING_FOR_LOAD). Once the order is loaded (LOADED and later) or in a terminal state (COMPLETED, FAILED, CANCELLED, EXPIRED), the request returns 409 and details.current_status carries the delivery’s current status. If a pickup is in progress within the cancellable window, it is cancelled along with the delivery.
Idempotency
The Direct Delivery API does not use a separate Idempotency-Key header. The external_delivery_id you set on the quote and create calls is the idempotency key:
POST /dd/v1/deliveries/quotewith the sameexternal_delivery_idreplaces the prior quote in place (race-safe via PostgresON CONFLICT); the response always reflects the latest quote.POST /dd/v1/deliverieswith anexternal_delivery_idwhose quote was already consumed returns409 QUOTE_ALREADY_CONSUMED; the response is final and safe to surface to the caller without retrying.
Webhook delivery has its own idempotency contract; see Idempotency on the webhook page.