Skip to content

/api-messaging-webhooks

Webhook patterns — receiving, sending, signature verification, and retry logic

shell
$ npx -y skills add agents-inc/skills --skill api-messaging-webhooks --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.
  • You can call itInvoke it directly when you want it.
  • Slash command/api-messaging-webhooks
How auto-invocation works

Context preview

The summary Claude sees to decide when to auto-load this skill.

Webhook patterns — receiving, sending, signature verification, and retry logic

SKILL.md

api-messaging-webhooks.SKILL.md
name: api-messaging-webhooks
description: Webhook patterns — receiving, sending, signature verification, and retry logic

Webhook Patterns

> **Quick Guide:** Verify signatures with HMAC-SHA256 using `crypto.createHmac` + `crypto.timingSafeEqual` on the **raw body bytes** -- never parsed JSON. Enforce idempotency by storing processed webhook IDs. Protect against replay attacks with timestamp validation. Return 200 immediately, process asynchronously. When sending, use exponential backoff with jitter and move exhausted retries to a dead letter queue.

---

<critical_requirements>

CRITICAL: Before Using This Skill

> **All code must follow project conventions in CLAUDE.md** (kebab-case, named exports, import ordering, `import type`, named constants)

**(You MUST verify signatures against the RAW request body -- never parsed/re-serialized JSON)**

**(You MUST use `crypto.timingSafeEqual` for signature comparison -- never `===` which leaks timing information)**

**(You MUST return 2xx immediately and process webhooks asynchronously -- synchronous processing causes timeouts and duplicate deliveries)**

**(You MUST enforce idempotency by checking a stored webhook ID before processing -- retries WILL send the same event multiple times)**

</critical_requirements>

---

**Auto-detection:** webhook, webhooks, HMAC, signature verification, createHmac, timingSafeEqual, webhook-signature, webhook-id, webhook-timestamp, idempotency key, replay attack, exponential backoff, dead letter queue, event routing, webhook handler, webhook endpoint, webhook delivery, webhook retry

**When to use:**

  • Receiving webhooks from external providers (payment processors, version control, messaging platforms)
  • Building a webhook-sending system to notify external consumers of events
  • Implementing signature verification for incoming webhook payloads
  • Adding retry logic with exponential backoff for outbound webhook delivery
  • Routing webhook events to type-safe handlers by event type

**When NOT to use:**

  • Real-time bidirectional communication (use WebSockets or Server-Sent Events)
  • Internal service-to-service communication where both sides are trusted and co-deployed
  • Simple polling scenarios where the consumer controls the fetch timing

**Key patterns covered:**

  • HMAC-SHA256 signature verification with timing-safe comparison
  • Replay attack protection with timestamp validation
  • Idempotency via stored webhook IDs with TTL
  • Type-safe event routing with discriminated unions
  • Outbound webhook delivery with exponential backoff and jitter
  • Dead letter queues for exhausted retries
  • Raw body handling to preserve signature integrity

**Detailed Resources:**

  • [examples/core.md](examples/core.md) - Receiving, signature verification, idempotency, event routing
  • [examples/sending.md](examples/sending.md) - Sending webhooks, retry logic, delivery tracking
  • [reference.md](reference.md) - Decision frameworks, header conventions, status code handling

---

<philosophy>

Philosophy

Webhooks are HTTP callbacks -- a producer POSTs a payload to a consumer's URL when an event occurs. The fundamental challenge is **trust and reliability**: the consumer must verify the payload is authentic (signature verification), not replayed (timestamp validation), and not processed twice (idempotency). The producer must handle delivery failures gracefully (retries with backoff) and not lose events permanently (dead letter queues).

**Core security principle:** The signature is computed over the exact bytes transmitted. Any transformation -- JSON parsing, re-serialization, whitespace normalization -- invalidates the signature. Always verify against the raw body.

**Core reliability principle:** Networks are unreliable. The consumer should acknowledge receipt immediately (return 2xx) and process asynchronously. The producer should retry with exponential backoff and eventually move to a dead letter queue.

**When to implement webhooks:**

  • Notifying external systems of events in near-real-time
  • Replacing polling for event-driven integrations
  • Building platform APIs that external developers consume

**When NOT to implement webhooks:**

  • When polling is simpler and latency requirements are relaxed (minutes, not seconds)
  • For internal pub/sub where a message broker is more appropriate
  • When the consumer cannot expose a public HTTP endpoint

</philosophy>

---

<patterns>

Core Patterns

Pattern 1: HMAC-SHA256 Signature Verification

The foundation of webhook security. The producer signs the payload with a shared secret; the consumer recomputes the signature and compares using timing-safe equality.

import { createHmac, timingSafeEqual } from "node:crypto";

const SIGNATURE_ALGORITHM = "sha256";
const SIGNATURE_ENCODING = "hex";

function verifySignature(rawBody: string, signature: string, secret: string): boolean {
  const expected = createHmac(SIGNATURE_ALGORITHM, secret)
    .update(rawBody)
    .digest(SIGNATURE_ENCODING);

  const expectedBuffer = Buffer.from(expected, "utf8");
  const receivedBuffer = Buffer.from(signature, "utf8");

  if (expectedBuffer.length !== receivedBuffer.length) return false;

  return timingSafeEqual(expectedBuffer, receivedBuffer);
}

**Why good:** uses `timingSafeEqual` to prevent timing attacks, operates on raw body bytes, length check before comparison prevents `timingSafeEqual` throwing on mismatched lengths

See [examples/core.md](examples/core.md) for the full handler with raw body extraction and error responses.

---

Pattern 2: Replay Attack Protection

Timestamp validation prevents attackers from re-sending captured webhook payloads. Reject payloads older than a tolerance window.

const MAX_TIMESTAMP_AGE_SECONDS = 300; // 5 minutes
const MS_PER_SECOND = 1000;

function isTimestampValid(timestampHeader: string): boolean {
  const webhookTime = parseInt(timestampHeader, 10);
  if (Number.isNaN(webhookTime)) return false;

  const currentT
Read more
Read it on GitHub ↗

Showing the first part of this file.

Ships withagents-inc-skills

The official skills marketplace for Agents Inc. 150+ skills covering everything from React and Prisma to Redis, ElevenLabs, and infrastructure tooling. Pick the skills that match your stack and install them via Claude Code. Need more control?

Get the whole plugin, auto-invoked