# RapidAPI Webhooks

Covers Enterprise Hub events only. The RapidAPI Enterprise Hub (Admin Panel > Events) sends an
HTTP POST to up to five callback URLs whenever something happens in the hub: an API is created,
a subscription changes, a user or team is added. Events are **not signed**. Every request carries
the hub's webhook secret key as plain text in the `x-rapidapi-webhook-secret` header, and your
endpoint authenticates the sender by comparing that header with the key you have stored.

This does not apply to the public rapidapi.com marketplace.

## When to Use This Skill

* How do I receive RapidAPI Enterprise Hub webhooks?
* How do I verify the `x-rapidapi-webhook-secret` header?
* Does RapidAPI sign webhook payloads? (No: use the shared secret key)
* How do I handle `API Created`, `Subscription Created` or `User Created` events?
* Why does my RapidAPI webhook endpoint return 401 after I generated a new key?

## Verification (core)

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

// Equal lengths first: timingSafeEqual throws on unequal-length buffers.
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 verifyRapidApiRequest(headers, secret = process.env.RAPIDAPI_WEBHOOK_SECRET) {
  if (!secret) return false;                              // never accept when unconfigured
  const received = headers['x-rapidapi-webhook-secret'];  // whole value, plain text
  return Boolean(received) && safeEqual(received, secret);
}

```

* Header: `x-rapidapi-webhook-secret: <secret key>`, matched case-insensitively. Compare the whole
  value; there is no prefix, HMAC or timestamp.
* Python: `hmac.compare_digest(a.encode(), b.encode())`. Encode both sides to bytes; passing `str`
  raises `TypeError` on non-ASCII input.
* Return `401` on a missing header or mismatch, `400` for a body that isn't a JSON object, `200`
  once handled.
* Read the body raw (`express.raw({ type: '*/*' })`) and authenticate before parsing it.

**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, make handlers
idempotent, and rotate the key with **Generate new** if it leaks.

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

## Event Types

Events are named like the display names below (the docs also show some in `UPPER.CASE` form, such
as `BILLINGPLAN.UPDATED`). The body format is not documented, so send a **Test event** from the
Admin Panel and read the real payload before relying on any field name. The examples read the
event type from the field named by `RAPIDAPI_EVENT_FIELD`; example payloads are illustrative.

| Event | Sent When |
| --- | --- |
| `API Created` | An API is created in the hub |
| `API Updated` | An API is updated |
| `API Deleted` | An API is deleted |
| `Subscription Created` | A subscription is created |
| `Subscription Updated` | A subscription is updated or deleted |
| `User Created` | A user is created |
| `Billing Plan Updated` | A billing plan is updated |

Many more exist (teams, apps, app keys, organizations, endpoints, documentation, approvals,
discussions, jobs); see [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rapidapi-webhooks/references/overview.md). One action can trigger
several events, for example creating an API also sends `API Updated` and `Subscription Created`.

## Environment Variables

```bash
RAPIDAPI_WEBHOOK_SECRET=your-webhook-secret-key   # Admin Panel > Events
RAPIDAPI_EVENT_FIELD=                             # optional: body field holding the event type

```

**Generate new** replaces the key; update the variable at the same time.

## Local Development

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

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

```

Use the printed URL as a callback URL on the Events tab. Hookdeck shows this setup note for the
RapidAPI source: "Covers Enterprise Hub events only."

## Resources

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rapidapi-webhooks/references/overview.md) - What the events are, event list, payload notes
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rapidapi-webhooks/references/setup.md) - Enable events, add callback URLs, find the secret key
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/rapidapi-webhooks/references/verification.md) - Header check details, gotchas, debugging 401s
* [examples/](https://github.com/hookdeck/webhook-skills/tree/main/skills/rapidapi-webhooks/examples/) - Runnable Express, Next.js and FastAPI handlers with tests