# Ably Webhooks

Covers Ably **outbound webhook integration rules** (generic HTTP endpoints). Lambda, Azure, Google Functions, Zapier and similar targets are different rule types.

## When to Use This Skill

* How do I receive Ably webhooks?
* How do I verify the `X-Ably-Signature` header?
* Why does my Ably webhook signature verification fail?
* How do I handle `channel.message`, `channel.presence`, `channel.lifecycle` or `channel.occupancy` events?
* How do I handle batched, enveloped, non-enveloped or msgpack Ably webhook payloads?

## Verification (core)

> **The HMAC key is the `keyValue` only.** An Ably API key looks like `appId.keyId:keyValue`. Use the part **after the `:`** as the HMAC key, not the whole key. Using the full API key is the most common reason verification fails.

Signing is **opt-in**: enable **Sign with key** on the integration rule. Ably then sends `X-Ably-Signature` (base64 HMAC-SHA256 of the **raw request body bytes**) and `X-Ably-Key` (names the API key used). There is no timestamp in the signature. The body may be JSON or msgpack and is signed either way.

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

function verifyAbly(rawBody /* Buffer */, signature, apiKey /* appId.keyId:keyValue */) {
  const keyValue = apiKey.slice(apiKey.indexOf(':') + 1); // secret part only
  const expected = crypto.createHmac('sha256', keyValue).update(rawBody).digest('base64');
  try {
    return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
  } catch {
    return false; // different lengths
  }
}

```

Read the body as raw bytes for **any** content type: `express.raw({ type: '*/*' })` in Express, `request.arrayBuffer()` in Next.js, `await request.body()` in FastAPI. Ably has no SDK helper for webhook verification, so all examples verify manually. See [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/ably-webhooks/references/verification.md) for gotchas.

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

## Payload Shapes

| Mode | What you receive |
| --- | --- |
| Enveloped (default) | `{ source, appId, channel, site, ruleId, messages | presence }` |
| Batched | `{ items: [{ webhookId, source, name, serial, timestamp, data: { channelId, ... } }] }`. Always iterate `items` |
| Non-enveloped | Raw data as the body; metadata in `x-ably-envelope-*` headers (not covered by the signature) |

Messages and presence entries are raw: `data` may need decoding with `Message.fromEncodedArray` / `PresenceMessage.fromEncodedArray`, and presence `action` is a number (`0` absent, `1` present, `2` enter, `3` leave, `4` update).

## Common Event Types

Events are identified by the `source` field (and `x-ably-envelope-source` header when not enveloped):

| Source | Description |
| --- | --- |
| `channel.message` | Messages published on a channel |
| `channel.presence` | Members enter, leave or update presence |
| `channel.lifecycle` | Channel created or discarded (`name` is `channel.opened` or `channel.closed`) |
| `channel.occupancy` | Number of users on a channel changed |

> **For the full reference**, see [Ably outbound webhooks](https://ably.com/docs/platform/integrations/webhooks)

## Environment Variables

```bash
ABLY_API_KEY=appId.keyId:keyValue   # the key selected in "Sign with key"; only keyValue is the HMAC key

```

## Local Development

```bash
# Start tunnel (no account needed)
npx hookdeck-cli listen 3000 ably --path /webhooks/ably

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/ably-webhooks/references/overview.md) - Ably webhook concepts, payload shapes, events
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/ably-webhooks/references/setup.md) - Create an integration rule and enable signing
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/ably-webhooks/references/verification.md) - Signature verification details and gotchas