Agent skill

Heroku Webhooks Skill

Receive and verify Heroku app webhooks. Use when setting up Heroku webhook handlers, debugging Heroku-Webhook-Hmac-SHA256 signature verification, or handling app events like api:release, api:build, api:dyno, api:formation, and api:addon-attachment.

Install this skill

npx skills add hookdeck/webhook-skills --skill 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:

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:

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:

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)ActionsDescription
api:releasecreate, updateNew release; with release phase you get create, update, update
api:buildcreate, updateBuild started / finished (check data.status)
api:appcreate, update, destroyApp created, changed, or deleted
api:dynocreateDyno started
api:formationupdate, destroyProcess type scaled or removed
api:addon-attachmentcreate, destroyAdd-on attached or detached
api:addon, api:collaborator, api:domain, api:sni-endpointsee overviewOther entities

For the full list, see Heroku App Webhooks.

Environment Variables

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

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

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 2, 2026

View on GitHub →