Webhooks Guide
Uber Direct notifies your application of delivery updates in real-time via two DaaS Webhooks: delivery_status
and courier_update
. This guide explains how to receive, authenticate, and process the notifications.
¶ Receiving Webhooks
Webhook notifications are sent as POST requests from Uber Direct to an Internet endpoint that you specify. When your endpoints are up and listening, you can add their URLs via the Direct Dashboard (direct.uber.com).
- Click the Developer tab on the left, followed by the Webhooks tab in the middle:
- Click Create Webhook
-
Fill in the Webhook URL with your service endpoint.
-
Choose which Webhook(s) should be sent to this URL. You can use one URL for both Webhook types, or a separate URL for each.
-
Click Save.
¶ Authenticating Webhooks
Each Webhook you create provides you with a Webhook Signing Key. This shared secret key is used by your application to verify that incoming messages to your Webhook endpoint are legitimately sent from Uber.
To get a Webhook’s signing key, click the triple dots next to it and select Edit:
When a Webhook POST message is sent to your endpoint, it includes the header X-Postmates-Signature, which is a SHA-256 hash of the message payload generated using the secret key. In other words, to verify the signature:
-
Take a SHA-256 HASH of the message using your secret key, perhaps using a standard HMAC function provided by your language (example below).
-
Compare the checksum to the hash in
X-Postmates-Signature
a. If it matches, process the message b. Else, ignore
Here is an example of a Python script that computes what the X-Postmates-Signature
should be, given a secret key and a message payload:
import hashlib, hmac
api_secret = 'c5c26d5a-70d6-46c7-a652-d7c09825ad29'
# Shortened for this example
payload = '{"kind": "event.courier_update", "location": {"lat": 37.7974109, "lng": -122.424145}}'
hmac.new(api_secret, payload, hashlib.sha256).hexdigest()
# → 'cdff8133fb065f8d37a2c1c94c3331b6a82766d14e7ea4faacc4886558cedd65'
¶ Processing Webhooks
¶ Delivery status
A Webhook of type event.delivery_status
will be sent each time the status
field of a delivery changes:
status | description |
---|---|
pending |
Delivery has been created successfully, but does not yet have a courier assigned |
pickup |
Courier is assigned and is en route to pick up the items |
pickup_complete |
Courier has picked up the items and has begun moving towards the dropoff |
dropoff |
Courier is moving towards the dropoff |
delivered |
Courier has completed the dropoff |
canceled |
Delivery has been canceled; for example by using the Cancel Delivery endpoint |
returned |
The delivery was canceled, and a new delivery was created to return items to the sender |
The delivery status Webhook event will contain a status
field to give you the new status, and a data
field which gives you an up-to-date copy of the delivery object / all of the delivery data.
Here is an example of a delivery_status
Webhook payload, showing that an order has reached pickup_complete state after satisfying barcode verification:
{
"status": "pickup_complete",
"kind": "event.delivery_status",
"created": "2022-04-14T17:39:18.287Z",
"live_mode": true,
"delivery_id": "XXXXXXXXXXXXXXXX",
"id": "evt_XXXXXXXXXXXXX",
"data": {
"id": "del_XXXXXXXXXXXXX",
"quote_id": "dqt_XXXXXXXXXXXXX",
"status": "pickup_complete",
"complete": false,
"kind": "delivery",
"pickup": {
"name": "XXXXXXXXX",
"phone_number": "+15555555555",
"address": "XXXXXXXXXXXXX, Test City, CA 99999-9999, US",
"detailed_address": {
"street_address_1": "XXXXXXXXXXXXX",
"street_address_2": "",
"city": "Test City",
"state": "CA",
"zip_code": "XXXXX-XXXX",
"country": "US"
},
"notes": "",
"location": {
"lat": 99.99999,
"lng": -99.99999
},
"verification_requirements": {
"barcodes": [
{
"type": "QR",
"value": "XXXXXXXXXXXXX-1"
}
]
},
"status": "completed",
"status_timestamp": "2022-04-14T17:39:18.187Z"
},
"dropoff": {
"name": "Zach Z.",
"phone_number": "+15555555555",
"address": "XXXXXXXXXXXXX, 406, Test City, CA, 99999-9999",
"detailed_address": {
"street_address_1": "XXXXXXXXXXXXX",
"street_address_2": "",
"city": "Test City",
"state": "",
"zip_code": "99999-9999",
"country": "US"
},
"notes": "",
"location": {
"lat": 99.9999,
"lng": -99.99999
},
"verification": {
"picture":
{
"image_url": "https://tb-static.uber.com/prod/file-upload/uploads/direct-image-capture/XXXXXXXXXXXXX"
},
"completion_location":
{
"lat": 99.9999,
"lng": -99.99999
}
},
"verification_requirements": {
"picture": true
}
},
"manifest": {
"reference": "XXXXXXXXXXXXX-1",
"description": "1 X Cardboard Box\n"
},
"manifest_items": [
{
"name": "Cardboard Box",
"quantity": 1,
"size": "medium",
"price": 0,
"dimensions": {
"length": 27,
"height": 19,
"depth": 12
},
"must_be_upright": false,
"weight": 150
}
],
"created": "2022-04-14T17:28:03.808Z",
"updated": "2022-04-14T17:39:18.187Z",
"pickup_ready": "2022-04-14T17:28:04Z",
"pickup_deadline": "2022-04-14T17:48:04Z",
"dropoff_ready": "2022-04-14T17:28:04Z",
"dropoff_deadline": "2022-04-14T18:47:30Z",
"pickup_eta": "2022-04-14T17:39:18.187Z",
"dropoff_eta": "2022-04-14T18:03:30.572Z",
"fee": 1549,
"currency": "usd",
"tracking_url": "https://www.ubereats.com/orders/XXXXXXXXXXXXX",
"undeliverable_action": "",
"courier_imminent": false,
"courier": {
"name": "Cori R.",
"vehicle_type": "car",
"phone_number": "+15555555555",
"location": {
"lat": 99.999999,
"lng": -99.99999
},
"img_href": "https://XXXXXXXXXXXXX.cloudfront.net/XXXXXXXXXXXXX",
"rating": "5.00",
"vehicle_make": "Toyota",
"vehicle_model": "Prius",
"location_description": "",
"vehicle_color": "dimgray"
},
"live_mode": true,
"undeliverable_reason": "",
"uuid": "XXXXXXXXXXXXX",
"external_id": "XXXXXXXXXXXXX-1",
"route_id": "rte_XXXXXXXXXXXXX"
},
"customer_id": "cus_XXXXXXXXXXXXX",
"developer_id": "dev_XXXXXXXXXXXXX",
"account_id": "acc_XXXXXXXXXXXXX",
"route_id": "rte_XXXXXXXXXXXXX"
}
Descriptions of all fields can be found in the Delivery Status API Reference
¶ Courier update
A Webhook of type event.courier_update
will be sent every 20 seconds, starting from when a Courier is assigned (i.e. when the status
transitions to pickup
). The payload provides lat
and long
fields to give your application the up-to-date location of the Courier.
Here is an example of a courier_update
Webhook payload. Like delivery_status
, courier_update
also includes the data
object containing an up-to-date copy of all delivery information.
{
"id": "evt_XXXXXXXXXXXXXXXXXXX",
"location": {
"lat": 12.345678,
"lng": -32.168454
},
"kind": "event.courier_update",
"live_mode": true,
"delivery_id": "del_1bqA1-XXXXXXXXXXXXXX",
"data": {
"id": "del_1bqA1-XXXXXXXXXXXXXXXX",
"quote_id": "dqt_1bqA1-XXXXXXXXXXXXXXXX",
"status": "delivered",
"complete": true,
"kind": "delivery",
"pickup": {
"name": "storename",
"phone_number": "+11111111111",
"address": "XXXXXXXXXXXXXXXXX",
"detailed_address": {
"street_address_1": "XXXXXXXXXXXXXXXX",
"street_address_2": "",
"city": "Portland",
"state": "OR",
"zip_code": "97210-1430",
"country": "US"
},
"notes": "",
"location": {
"lat": 99.99999,
"lng": -99.99999
},
"verification": {
"barcodes": [
{
"type": "QR",
"value": "XXXXXXXXXX-1",
"scan_result": {
"outcome": "SUCCESS",
"timestamp": "2022-03-29T22:43:43.839Z"
}
}
]
},
"verification_requirements": {
"barcodes": [
{
"type": "QR",
"value": "XXXXXXXXXX-1"
}
]
},
"status": "completed",
"status_timestamp": "2022-03-29T22:43:44.965Z"
},
"dropoff": {
"name": "Zach Z.",
"phone_number": "+11111111111",
"address": "XXXXXXXXXXXXXXXX",
"detailed_address": {
"street_address_1": "XXXXXXXXXXXXXXXX",
"street_address_2": "",
"city": "Portland",
"state": "",
"zip_code": "97209",
"country": "US"
},
"notes": "",
"location": {
"lat": 99.99999,
"lng": -99.99999
},
"verification": {
"picture": {
"image_url": "https://tb-static.uber.com/XXXXXXXXXXXXXXXXXXXX"
}
},
"verification_requirements": {
"picture": true
},
"status": "completed",
"status_timestamp": "2022-03-29T22:57:20.129Z"
},
"manifest": {
"reference": "XXXXXXXXX-1",
"description": "1 x Cardboard Box\n"
},
"manifest_items": [
{
"name": "Cardboard Box",
"quantity": 1,
"size": "medium",
"price": 0,
"dimensions": {
"length": 27,
"height": 37,
"depth": 10
},
"must_be_upright": false,
"weight": 120
}
],
"created": "2022-03-29T21:50:27.554Z",
"updated": "2022-03-29T22:52:11.404Z",
"pickup_ready": "2022-03-29T21:50:27Z",
"pickup_deadline": "2022-03-29T22:10:27Z",
"dropoff_ready": "2022-03-29T21:50:27Z",
"dropoff_deadline": "2022-03-29T23:10:27Z",
"pickup_eta": "2022-03-29T22:43:44.965Z",
"dropoff_eta": "2022-03-29T22:57:14.161Z",
"fee": 500,
"currency": "usd",
"tracking_url": "https://www.ubereats.com/orders/XXXXXXXXXXXXXXXX",
"undeliverable_action": "",
"courier_imminent": true,
"courier": {
"name": "Cori R.",
"vehicle_type": "car",
"phone_number": "+11111111111",
"location": {
"lat": 45.432121,
"lng": -123.12341
},
"img_href": "https://XXXXXXXXXXXXXXXX.cloudfront.net/XXXXXXXXXXXXXXXX",
"rating": "5.00",
"vehicle_make": "Ford",
"vehicle_model": "Focus",
"location_description": "",
"vehicle_color": "white"
},
"live_mode": true,
"undeliverable_reason": "",
"uuid": "XXXXXXXXXXXXXXXX",
"external_id": "XXXXXXXXX-1",
"route_id": "rte_XXXXXXXXXXXXXXXX"
},
"created": "2022-03-29T22:56:45.895Z"
}
Descriptions of all fields can be found in the Courier Update API Reference
¶ Next Steps
- API Reference: Delivery Status, Courier Update