# RudderStack Webhooks

RudderStack's **HTTP Webhook destination** forwards events (`track`, `identify`, `page`,
`screen`, `group`, `alias`) to your endpoint. Webhooks are **not signed**. With Basic Auth
selected, every request carries `Authorization: Basic base64(username:password)` and your
endpoint authenticates the request by comparing those credentials with the ones you stored.

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.

## When to Use This Skill

* How do I receive RudderStack webhooks?
* How do I verify the HTTP Webhook destination's Basic Auth header?
* Does RudderStack sign webhook payloads? (No: use the shared Basic credential)
* How do I handle `track` and `identify` events from RudderStack?
* Why does my RudderStack webhook endpoint return 401?

## Verification (core)

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

// Hash both sides: equal-length buffers, so timingSafeEqual never throws.
const safeEqual = (a, b) => crypto.timingSafeEqual(
  crypto.createHash('sha256').update(a, 'utf8').digest(),
  crypto.createHash('sha256').update(b, 'utf8').digest());

function verifyRudderstackRequest(headers, user, pass) {
  const m = /^basic\s+([A-Za-z0-9+/]+={0,2})\s*$/i.exec(headers['authorization'] || '');
  if (!m || !user || !pass) return false;
  const decoded = Buffer.from(m[1], 'base64').toString('utf8');
  const i = decoded.indexOf(':');                 // split on the first colon
  if (i === -1) return false;
  const userOk = safeEqual(decoded.slice(0, i), user);   // evaluate both,
  const passOk = safeEqual(decoded.slice(i + 1), pass);  // no short-circuit
  return userOk && passOk;
}

```

* Header: `Authorization: Basic base64(username:password)`; the scheme is case-insensitive.
* Python: `hmac.compare_digest` on **bytes** (encode both sides; `str` raises on non-ASCII).
* Return `401` on a missing, malformed or mismatched header, `400` for an unparseable body,
  `200` once handled. RudderStack aborts a `4XX` with no retries and retries `5XX` and `429` for
  3 hours, so return `503` for a temporary problem.
* The method is user-chosen: accept `POST`, `PUT`, `PATCH`, `GET` and `DELETE`, and accept an
  empty body.
* Read the body raw (`express.raw({ type: '*/*' })`) and authenticate before parsing it.
* Bearer Token and API Key auth types are not covered.

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

## Event Types

With "Send the event payload as is" (the default) the body is the RudderStack event and
`type` says which kind; for `track`, `event` holds the event name. Batching sends an array of
events; custom mappings can emit any shape.

| `type` | Sent When |
| --- | --- |
| `track` | A user performs an action (`event`, `properties`) |
| `identify` | A user is identified (`traits`) |
| `page` | A web page is viewed |
| `screen` | A mobile screen is viewed |
| `group` | A user is associated with a group or account |
| `alias` | Two user identities are merged |

## Environment Variables

```bash
RUDDERSTACK_WEBHOOK_USERNAME=your-username   # Destination > Authentication > Basic Auth
RUDDERSTACK_WEBHOOK_PASSWORD=your-password

```

## Local Development

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

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

```

Use the printed URL as the destination's Base URL.

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rudderstack-webhooks/references/overview.md) - What RudderStack webhooks are, event types and payload shapes
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rudderstack-webhooks/references/setup.md) - Add the HTTP Webhook destination with Basic Auth
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rudderstack-webhooks/references/verification.md) - Basic auth check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/rudderstack-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests