Agent skill

beehiiv Webhooks Skill

Receive and verify beehiiv newsletter platform webhooks, delivered through Svix. Use when setting up a beehiiv webhook endpoint, debugging svix-id / svix-timestamp / svix-signature verification (whsec_ secret), or handling events like subscription.created, subscription.upgraded, post.sent, post.scheduled, newsletter_list_subscription.subscribed and survey.response_submitted.

Install this skill

npx skills add hookdeck/webhook-skills --skill beehiiv-webhooks


beehiiv is a newsletter platform. Its webhooks report subscriber, post, survey and podcast activity. beehiiv delivers them through Svix, so every request carries svix-id, svix-timestamp and svix-signature headers that you verify with your endpoint's signing secret. Webhooks need a paid beehiiv plan (Lite and above).

When to Use This Skill

  • How do I receive beehiiv webhooks?
  • How do I verify a beehiiv webhook signature (svix-signature)?
  • Where do I find my beehiiv webhook signing secret?
  • How do I handle subscription.created, subscription.upgraded or post.sent events?
  • Why is my beehiiv webhook signature verification failing?
  • Why are Hookdeck retries of beehiiv webhooks rejected after a few minutes?

Verification (core)

HeaderValue
svix-idMessage ID, the same on every retry
svix-timestampUnix seconds when the attempt was sent
svix-signatureOne or more space-separated v1,<base64> entries

Signed content is {svix-id}.{svix-timestamp}.{raw body}, HMAC-SHA256, base64. The key is the base64-decoded part of the endpoint secret after whsec_. The secret is the endpoint's signing secret from Settings > Webhooks (BEEHIIV_WEBHOOK_SECRET). Verify with the svix library (npm svix, PyPI svix):

import { Webhook } from 'svix';

// rawBody: the exact request body string, NOT re-serialised JSON
function verifyBeehiivWebhook(rawBody, headers, secret = process.env.BEEHIIV_WEBHOOK_SECRET) {
  new Webhook(secret).verify(rawBody, {
    'svix-id': headers['svix-id'],
    'svix-timestamp': headers['svix-timestamp'],
    'svix-signature': headers['svix-signature'],
  }); // throws on a bad signature or stale timestamp; respond 400
  return JSON.parse(rawBody); // parse only after verification
}

Python: from svix.webhooks import Webhook, then Webhook(secret).verify(raw_body, headers) (raises WebhookVerificationError).

Retries and replays: the svix library always enforces a fixed 5-minute timestamp window. Hookdeck retries and replays resend the original svix-timestamp, so the library rejects them once they are more than 5 minutes old. If you retry or replay late, use the manual verifier in references/verification.md, where the window can be dropped or widened.

Missing headers or a bad signature: respond 400 (or 401). In Express, read the raw body with express.raw({ type: '*/*' }) so any content type verifies.

For complete handlers with tests, see examples/express/, examples/nextjs/, examples/fastapi/.

Event Envelope

{ "uid": "evt_...", "event_type": "subscription.created",
  "event_timestamp": 1792922400, "data": { } }

Dispatch on event_type. uid identifies the event; the svix-id header is stable across retries and works as a dedupe key too.

Common Event Types

EventFired when
post.sentA post is sent
post.updatedA post is updated
post.scheduledA post is scheduled
subscription.createdA subscription is created
subscription.confirmedA subscriber confirms their subscription
subscription.deletedA subscription is deleted
subscription.upgraded / subscription.downgradedA subscriber moves to a higher / lower tier
subscription.paused / subscription.resumedA subscription is paused / resumed
newsletter_list_subscription.subscribedA subscriber joins a newsletter list
survey.response_submittedA survey response is submitted
podcasts.episode.publishedA podcast episode is published

beehiiv lists more event types; see references/overview.md and the beehiiv webhook docs.

Environment Variables

BEEHIIV_WEBHOOK_SECRET=whsec_xxxxx   # endpoint signing secret; handlers fail closed (500) without it

Local Development

# Express / Next.js (use 8000 for FastAPI). No install or account required.
npx hookdeck-cli listen 3000 beehiiv --path /webhooks/beehiiv

Add the printed URL as an endpoint under Settings > Webhooks in beehiiv.

Reference Materials


Repository

hookdeck/webhook-skills

v0.1.0 · MIT · Updated Nov 6, 2026

View on GitHub →