# Rebrandly Webhooks

Rebrandly (branded short links) sends a JSON webhook for link clicks. There are two products:
enterprise **Clickstream** webhooks, where you give Rebrandly an endpoint URL, an HTTP method
(POST or PUT) and an authentication header key and value; and the self-serve **Webhooks** feature
in account settings.

> Rebrandly webhooks are not signed. Add an authentication header to the webhook and enter it here.

Requests are unsigned. You authenticate the sender with a secret header you add yourself.

## When to Use This Skill

* How do I receive Rebrandly webhooks?
* How do I authenticate Rebrandly Clickstream requests?
* Does Rebrandly sign webhook payloads? (No: use a shared header)
* How do I handle Rebrandly click events (`data[]` batches)?
* Why does my Rebrandly webhook endpoint return 401?

## Verification (core)

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

function safeEqual(a, b) {
  const ba = Buffer.from(String(a), 'utf8');
  const bb = Buffer.from(String(b), 'utf8');
  return ba.length === bb.length && crypto.timingSafeEqual(ba, bb);
}

function verifyRebrandlyRequest(headers, secret = process.env.REBRANDLY_WEBHOOK_SECRET,
    headerName = process.env.REBRANDLY_WEBHOOK_HEADER || 'Authorization') {
  if (!secret) return false;                       // never accept when unconfigured
  const received = headers[headerName.toLowerCase()];
  return typeof received === 'string' && received.length > 0 && safeEqual(received, secret);
}

```

* The header name is yours: set `REBRANDLY_WEBHOOK_HEADER` (default `Authorization`), look it up
  case-insensitively, and compare the **whole** value with `REBRANDLY_WEBHOOK_SECRET`. Do not
  strip or parse a `Bearer ` prefix; if you typed one at Rebrandly, it is part of the secret.
* Rebrandly's own blog names the self-serve header inconsistently (`X-Rebrandly-Secret` and
  `apikey`). Capture one real delivery and set `REBRANDLY_WEBHOOK_HEADER` to the header that arrives.
* Missing header or mismatch: `401`. Check it first, for every HTTP method.
* Python: `hmac.compare_digest` on bytes (encode both sides; `str` raises on non-ASCII).
* Read the body raw (`express.raw({ type: '*/*' })`) and parse it only after the check. Handle an
  empty body.
* **Security limits:** 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.

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

## HTTP Methods

Clickstream uses the POST or PUT method you give Rebrandly at setup, so the examples accept GET,
POST, PUT, PATCH and DELETE on `/webhooks/rebrandly`. Hookdeck's Rebrandly source pre-selects POST
without managing the method, so any other method the sender uses must also be allowed on the source.

## Event Types

Only click events exist; there is no event-type field. The body is
`{ "data": [ click, ... ], "key": "..." }`. Loop over `data[]`.

| Event | Sent When |
| --- | --- |
| `click` | A short link is clicked (one entry per click in `data[]`) |

Each click has `timestamp`, `client` (`language`, `location`, `agent`, `session`), `referral` and
`route` (link id, `slashtag`, `creator`, `domain`, `destination`). Each event is sent once; there are no retries.

## Environment Variables

```bash
REBRANDLY_WEBHOOK_HEADER=Authorization        # header name you gave Rebrandly
REBRANDLY_WEBHOOK_SECRET=your-shared-secret   # exact, whole header value

```

## Local Development

Rebrandly can't reach `localhost`. Tunnel with the Hookdeck CLI (no account required):

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

```

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rebrandly-webhooks/references/overview.md) - Rebrandly webhooks, click payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rebrandly-webhooks/references/setup.md) - Configure the authentication header and endpoint
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rebrandly-webhooks/references/verification.md) - Header check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/rebrandly-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests