TerminalSkills/skills

webhook-processor

Build and configure webhook processing systems with retry logic, signature verification, and dead letter queues.

View source

How to use

  1. Copy the installation command and review the source package before installing it in your own agent environment.
  2. Check the source document for required tools, credentials and supported hosts.
  3. Describe your input and desired deliverable; review the output against the source material.
npx skills add https://github.com/TerminalSkills/skills --skill webhook-processor

Before you start

  • Installation does not include a model subscription, API allowance or permission to access your files.
  • Repository stars and installation counts describe activity, not an independent quality or security test.
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Webhook Processor

Overview

This skill helps you build production-grade webhook ingestion endpoints that accept incoming HTTP callbacks, verify their authenticity, and process them reliably with exponential backoff retries and dead letter queues. It covers signature validation, idempotency keys, and graceful failure handling.

Instructions

1. Scaffold the webhook endpoint

Create an HTTP endpoint that accepts POST requests. Immediately return a 200 status before processing — webhook senders expect fast acknowledgment.

typescript
// webhook-receiver.ts
import express from "express";
import crypto from "crypto";
import { Queue } from "bullmq";

const app = express();
app.use(express.raw({ type: "application/json" }));

const webhookQueue = new Queue("webhooks", {
  connection: { host: "localhost", port: 6379 },
});

app.post("/webhooks/:source", async (req, res) => {
  // GitHub's header; other providers name theirs differently, so check their docs.
  const signature = req.headers["x-hub-signature-256"] as string | undefined;
  const idempotencyKey =
    req.headers["x-idempotency-key"] ||
    crypto.createHash("sha256").update(req.body).digest("hex");

  await webhookQueue.add(
    "process",
    {
      source: req.params.source,
      payload: req.body.toString(),
      signature,
      idempotencyKey,
      receivedAt: new Date().toISOString(),
    },
    {
      jobId: String(idempotencyKey),
      attempts: 5,
      backoff: { type: "exponential", delay: 3000 },
    }
  );

  res.status(200).json({ received: true });
});

2. Verify webhook signatures

Always validate the signature before processing, over the raw request bytes (the express.raw middleware above keeps them intact). GitHub sends X-Hub-Signature-256: sha256=<hex HMAC of the body>. Each provider uses its own header and format:

typescript
function verifySignature(
  payload: string,
  signature: string | undefined,
  secret: string,
  scheme: "hmac-sha256" | "hmac-sha1"
): boolean {
  if (!signature) return false;
  const algo = scheme === "hmac-sha256" ? "sha256" : "sha1";
  const prefix = scheme === "hmac-sha256" ? "sha256=" : "sha1=";
  const expected = Buffer.from(
    prefix + crypto.createHmac(algo, secret).update(payload, "utf8").digest("hex")
  );
  const received = Buffer.from(signature);
  // timingSafeEqual throws when the lengths differ, so compare lengths first
  return received.length === expected.length && crypto.timingSafeEqual(expected, received);
}

3. Implement the worker with retry logic

Process jobs from the queue. Failed jobs retry with exponential backoff. After all retries exhaust, move to a dead letter queue.

typescript
import { Worker, UnrecoverableError } from "bullmq";

const worker = new Worker(
  "webhooks",
  async (job) => {
    const { source, payload, signature } = job.data;
    const secret = getSecretForSource(source);
    if (!verifySignature(payload, signature, secret, "hmac-sha256")) {
      // A plain Error would be retried with backoff; UnrecoverableError fails the job at once.
      throw new UnrecoverableError("Invalid webhook signature");
    }
    const event = JSON.parse(payload);
    await routeEvent(source, event);
  },
  {
    connection: { host: "localhost", port: 6379 },
    limiter: { max: 50, duration: 1000 },
  }
);

worker.on("failed", (job, err) => {
  if (job && job.attemptsMade >= 5) {
    console.error(`Dead letter: job ${job.id} — ${err.message}`);
    // Move to dead letter queue for manual inspection
  }
});

4. Add idempotency tracking

Prevent double-processing with a deduplication store:

typescript
import Redis from "ioredis";
const redis = new Redis();

async function isProcessed(key: string): Promise<boolean> {
  const result = await redis.set(key, "1", "EX", 86400, "NX");
  return result === null; // null means key already existed
}

Examples

Example 1: Payment provider webhook

Prompt: "Set up a webhook endpoint to receive payment events. It should verify HMAC-SHA256 signatures, retry failed processing up to 5 times with exponential backoff, and log dead letter events."

Agent output:

  • Creates src/webhooks/payment-handler.ts with signature verification using the provider's signing secret
  • Creates src/workers/payment-worker.ts with BullMQ retry config (5 attempts, exponential backoff with a 3000 ms base: waits of 3 s, 6 s, 12 s, 24 s, since BullMQ waits 2^(attempts-1) × delay)
  • Creates src/utils/dead-letter.ts that stores failed events in a dead_letters database table
  • Adds integration test that simulates an invalid signature and verifies rejection

Example 2: Version control platform webhook

Prompt: "Build a webhook handler for repository push events that triggers CI builds. Include idempotency so duplicate deliveries don't start duplicate builds."

Agent output:

  • Creates src/webhooks/repo-handler.ts that validates the event type and extracts commit SHA
  • Uses the commit SHA as the idempotency key — same commit never triggers two builds
  • Creates src/workers/build-trigger.ts that enqueues build jobs only for new commits
  • Adds a Redis-backed deduplication check with 24-hour TTL

Guidelines

  • Always return 200 immediately — process asynchronously. Webhook senders timeout after 5-30 seconds and will retry, causing duplicates.
  • Use `crypto.timingSafeEqual` for signature comparison to prevent timing attacks.
  • Set idempotency key TTL to at least as long as the provider's retry window, which each provider documents. Check it before picking a TTL.
  • Monitor your dead letter queue — set up alerts when it grows beyond a threshold.
  • Log the raw payload before processing — invaluable for debugging malformed events.
  • Rate limit your worker to avoid overwhelming downstream services during webhook storms.
  • Handle schema changes gracefully — webhook payloads evolve. Use optional chaining and validate required fields explicitly.
from this repository

More skills

All skills
TerminalSkills
Community

3dsmax-rendering

Scripts and configures production rendering in Autodesk 3ds Max with the V-Ray and Corona renderers: output size and files, render elements, denoising, light mix, batch and command-line rendering, and network rendering. Use when a user asks to set up a production render, render several cameras in one batch, render from the command line or on a render farm, add render passes for compositing, or cut render time for archviz and product shots.

installs
0
GitHub stars
180
Updated
Oct 25
TerminalSkills
Community

3dsmax-scripting

Covers scripting Autodesk 3ds Max, the 3D modeling and rendering application, with MAXScript and Python (pymxs): scene manipulation, object creation, material assignment, camera and light setup, batch operations, and file I/O. Use when tasks involve automating repetitive 3ds Max workflows, batch processing scenes, running scripts headless with 3dsmaxbatch, creating custom tools, or scripting scene setup for archviz, product visualization, or VFX.

installs
0
GitHub stars
180
Updated
Oct 25
TerminalSkills
Community

3proxy

3proxy is a small open-source proxy server that runs HTTP/HTTPS, SOCKS4/5, SNI and TCP/UDP port-mapping proxies from one config file. Use when a user asks to set up an HTTP or SOCKS5 proxy, add proxy users and passwords, write 3proxy access rules, chain or rotate upstream (parent) proxies, limit bandwidth, connections or monthly traffic per user, run 3proxy in Docker, or fix a 3proxy.cfg that will not start.

installs
0
GitHub stars
180
Updated
Oct 25
TerminalSkills
Community

a2a-protocol

Builds Agent2Agent (A2A) servers and clients, the open protocol (originally from Google, now under the Linux Foundation) that lets AI agents from different frameworks call each other. Use when the user wants to create an A2A-compliant agent, build an Agent Card, implement task management, connect agents across frameworks, set up agent discovery, handle streaming responses, implement push notifications, or orchestrate multi-agent workflows. Trigger words: a2a, agent to agent, agent2agent, a2a pro

installs
0
GitHub stars
180
Updated
Oct 25