# DoorDash Drive Webhooks

DoorDash Drive (the Drive delivery API) sends webhooks to your server as a delivery moves through
Dasher assignment, pickup, dropoff, cancellation and return. Payloads are **not signed**. The only
credential is the text you enter in the Developer Portal, which DoorDash sends as the
`Authorization` header.

## When to Use This Skill

* How do I receive DoorDash Drive webhooks?
* How do I verify the DoorDash Drive `Authorization` header?
* Does DoorDash sign webhook payloads? (No: static header credential only)
* Why does my DoorDash Drive webhook endpoint return 401?
* How do I handle `DASHER_PICKED_UP`, `DASHER_DROPPED_OFF` or `DELIVERY_CANCELLED` events?

## Verification (core)

In the Developer Portal (Webhooks), pick **Basic Auth** and enter the text you want DoorDash to send
in the `Authorization` header. Despite the label, DoorDash sends that text **verbatim**: it is often a
bare token, not base64 `user:pass`. Treat the **whole header value** (scheme prefix included) as the
secret. Don't strip a prefix and don't decode it as HTTP Basic.

```javascript
const crypto = require('crypto');

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
function safeEqual(a, b) {
  const ha = crypto.createHash('sha256').update(String(a)).digest();
  const hb = crypto.createHash('sha256').update(String(b)).digest();
  return crypto.timingSafeEqual(ha, hb);
}

function verifyDoorDashDriveRequest(headers, expected = process.env.DOORDASH_DRIVE_AUTHORIZATION) {
  if (!expected) return false;                  // never accept when unconfigured
  const received = headers['authorization'];    // full value, exactly as you entered it
  return Boolean(received) && safeEqual(received, expected);
}

```

Return `401` when this fails, `400` for a body that isn't a JSON object, and `200` once handled
(DoorDash sends each event up to 3 times unless it gets `200 OK`). Read the body raw
(`express.raw({ type: '*/*' })`) and parse JSON only after the check. Python uses
`hmac.compare_digest` on bytes (encode both sides); see [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/doordash-drive-webhooks/references/verification.md).

**What this does and doesn't give you:** a static shared credential authenticates the sender, not the
body, and gives no replay protection (no signature, no timestamp). Use HTTPS and rotate the
credential if it leaks. OAuth is the other portal option; this skill doesn't cover it.

> **For complete handlers with tests**, see [examples/express/](https://github.com/hookdeck/webhook-skills/tree/main/skills/doordash-drive-webhooks/examples/express/),
> [examples/nextjs/](https://github.com/hookdeck/webhook-skills/tree/main/skills/doordash-drive-webhooks/examples/nextjs/), [examples/fastapi/](https://github.com/hookdeck/webhook-skills/tree/main/skills/doordash-drive-webhooks/examples/fastapi/).

## Event Types

Delivery webhooks carry `event_name` in the body:

| `event_name` | Fires when |
| --- | --- |
| `DASHER_CONFIRMED` | A Dasher accepted the delivery |
| `DASHER_CONFIRMED_PICKUP_ARRIVAL` | Dasher arrived at pickup |
| `DASHER_PICKED_UP` | Dasher picked up the delivery |
| `DASHER_CONFIRMED_DROPOFF_ARRIVAL` | Dasher arrived at dropoff |
| `DASHER_DROPPED_OFF` | Delivery dropped off (complete) |
| `DELIVERY_CANCELLED` | Delivery cancelled (see `cancellation_reason`) |
| `DELIVERY_RETURN_INITIALIZED`, `DASHER_CONFIRMED_RETURN_ARRIVAL`, `DELIVERY_RETURNED` | Return-to-pickup deliveries only |
| `DELIVERY_BATCHED` | Pre-staged batch deliveries (with `force_batch_id`) |
| `dasher_enroute_to_pickup`, `dasher_enroute_to_dropoff`, `dasher_enroute_to_return` | Opt-in tracking, Dasher location every 30s |

**Refund webhooks have no `event_name`**: the data is nested under `event_data` (`reason`, `amount`,
`currency_code`, ...) and DoorDash must approve you for them.

## Environment Variables

```bash
DOORDASH_DRIVE_AUTHORIZATION=replace-with-the-exact-text-you-entered   # full Authorization value

```

## Local Development

```bash
npx hookdeck-cli listen 3000 doordash-drive --path /webhooks/doordash-drive

```

No account required. Use the printed URL as the webhook URL in the Developer Portal (HTTPS only; one
endpoint per environment, Sandbox and Production).

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/doordash-drive-webhooks/references/overview.md) - Event types, payload fields, retries, refunds
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/doordash-drive-webhooks/references/setup.md) - Configure the endpoint in the Developer Portal
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/doordash-drive-webhooks/references/verification.md) - Header check in Node, Python and Next.js, gotchas
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/doordash-drive-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests