# Heroku Webhooks

## When to Use This Skill

* How do I receive Heroku app webhooks?
* How do I verify the `Heroku-Webhook-Hmac-SHA256` signature?
* How do I handle `api:release` or `api:build` events (deploy notifications)?
* Why is my Heroku webhook signature verification failing?
* How do I use `heroku webhooks:add` with `--secret` and `--authorization`?

## Verification (core)

Heroku sends `Heroku-Webhook-Hmac-SHA256`: the **base64** HMAC-SHA256 of the **raw request body**, keyed with the webhook secret. The secret is used as a raw string (not base64-decoded). There is no timestamp or webhook ID header, and Heroku has no webhook verification SDK, so verification is manual.

Node:

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

function verify(rawBody, hmacHeader, secret) {
  if (!hmacHeader) return false;
  const expected = crypto.createHmac('sha256', secret).update(rawBody).digest('base64');
  try {
    return crypto.timingSafeEqual(Buffer.from(hmacHeader), Buffer.from(expected));
  } catch {
    return false; // different lengths
  }
}

```

Python:

```python
import base64, hashlib, hmac

def verify(raw_body: bytes, hmac_header: str, secret: str) -> bool:
    if not hmac_header:
        return False
    expected = base64.b64encode(
        hmac.new(secret.encode(), raw_body, hashlib.sha256).digest()
    ).decode()
    return hmac.compare_digest(hmac_header, expected)

```

> **Optional extra**: if you subscribed with `--authorization`, Heroku also sends that exact value in the `Authorization` header. Compare it yourself; it is not a signature.
> 
> **Respond with any 2xx** (Heroku recommends `204 No Content`); the body is ignored.

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

## Common Event Types

A subscription lists entities with `-i`; each delivery carries a `resource` (the entity) and an `action` (`create`, `update`, or `destroy`) plus `data`.

| Entity (`-i`) | Actions | Description |
| --- | --- | --- |
| `api:release` | create, update | New release; with release phase you get create, update, update |
| `api:build` | create, update | Build started / finished (check `data.status`) |
| `api:app` | create, update, destroy | App created, changed, or deleted |
| `api:dyno` | create | Dyno started |
| `api:formation` | update, destroy | Process type scaled or removed |
| `api:addon-attachment` | create, destroy | Add-on attached or detached |
| `api:addon`, `api:collaborator`, `api:domain`, `api:sni-endpoint` | see overview | Other entities |

> **For the full list**, see [Heroku App Webhooks](https://devcenter.heroku.com/articles/app-webhooks).

## Environment Variables

```bash
HEROKU_WEBHOOK_SECRET=your_webhook_secret          # --secret value, or the one the CLI printed once
HEROKU_WEBHOOK_AUTHORIZATION=Bearer your_token     # Optional: the --authorization value

```

## Local Development

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

```

## Reference Materials

* [references/overview.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/heroku-webhooks/references/overview.md) - Heroku webhook concepts, entities, payload shape
* [references/setup.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/heroku-webhooks/references/setup.md) - `heroku webhooks:add` and secret handling
* [references/verification.md](https://github.com/hookdeck/webhook-skills/blob/main/skills/heroku-webhooks/references/verification.md) - Signature verification details and gotchas