# Redo Webhooks

Redo (e-commerce returns and exchanges) sends a `POST` with a JSON body to your HTTPS endpoint
when a return is created or updated. Payloads are **not signed**. The only authentication is a
static `Authorization: Bearer <your-subscriber-secret>` header, where the secret is a value you
generate and supply when you create the webhook subscription.

## When to Use This Skill

* How do I receive Redo webhooks?
* How do I verify the Redo `Authorization: Bearer` header on a webhook?
* Does Redo sign webhook payloads? (No: shared secret in the `Authorization` header only)
* Why does my Redo webhook endpoint return 401?
* How do I handle `return.created`, `return.updated` and backfill events?

## Verification (core)

Redo sends `Authorization: Bearer <your-subscriber-secret>`. The examples compare the **whole
header value** to the configured key: set `REDO_AUTHORIZATION` to the full value as Redo sends
it, **including the `Bearer ` prefix**. Don't strip, parse or base64-decode anything.

```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 verifyRedoRequest(headers, expected = process.env.REDO_AUTHORIZATION) {
  if (!expected) return false;                  // never accept when unconfigured
  const received = headers['authorization'];    // full value, e.g. "Bearer your-subscriber-secret"
  return Boolean(received) && safeEqual(received, expected);
}

```

Return `401` when this fails (missing header or mismatch), `400` for a body that isn't a JSON
object, and `2xx` once handled (Redo wants a 2xx within 5 seconds, and retries otherwise). Read
the body raw (`express.raw({ type: '*/*' })`) so any content type works, and parse it only after
the credential check. Python and Next.js equivalents are in
[references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/redo-webhooks/references/verification.md).

> **Security note:** a static shared credential authenticates the *sender*, not the *body*, and
> gives **no replay protection** (no signature, no timestamp). Anyone who captures one request
> can replay it, so use HTTPS only, keep the secret out of logs and source control, and rotate
> it if it leaks (create a subscription with a new `secret`, then delete the old one; the docs
> show `PATCH` changing only `topics`).

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

## Hookdeck Source Setup

In Hookdeck, create a source of type **Redo** (`REDO`). Hookdeck shows this setup note:

> Paste the secret set on the Redo webhook subscription.

Paste the bare secret into the **Subscription Secret** field, without `Bearer `. Hookdeck accepts
the `Authorization` header with or without the `Bearer ` prefix.

## Event Types

Subscribe with the `topics` array. The payload's `type` field carries the short form:

| Topic | Payload `type` | Triggered when |
| --- | --- | --- |
| `return.created` | `created` | A customer or team member creates a return |
| `return.updated` | `updated` | A return changes (status, items, ...) |
| (sent at setup or replay) | `backfill` | A historical event sent during webhook setup or replay |

The body is `{ "type", "at", "merchantName", "return": {...}, "order": {...} }`. Handle
`backfill` gracefully. Events are ordered per return, not across returns, so order by `at`.

## Environment Variables

```bash
REDO_AUTHORIZATION=Bearer your-subscriber-secret   # full header value, "Bearer " included

```

## Local Development

```bash
npx hookdeck-cli listen 3000 redo --path /webhooks/redo

```

No account required. Use the printed URL as the `url` when creating the Redo webhook subscription.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/redo-webhooks/references/overview.md) - Return events, topics vs payload types, payload fields
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/redo-webhooks/references/setup.md) - Creating the subscription with `POST /v2.2/stores/{storeId}/webhooks`
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/redo-webhooks/references/verification.md) - Header check in Node, Python and Next.js, gotchas
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/redo-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests