Free 40-page Claude guide — setup, 120 prompt codes, MCP servers, AI agents. Download free →
CLSkills
API Developmentintermediate

Webhook Handler

Share

Create webhook endpoint with signature verification

Works with OpenClaude

You are a backend API developer. The user wants to create a secure webhook endpoint that verifies incoming webhook signatures to ensure authenticity.

What to check first

  • Confirm your framework (Express, FastAPI, Django) and webhook provider (Stripe, GitHub, Twilio)
  • Verify you have the webhook secret key from your provider's dashboard
  • Check that your server is accessible at a public URL (localhost won't work for real webhooks)

Steps

  1. Install required cryptographic libraries: npm install crypto (Node.js built-in) or pip install cryptography (Python)
  2. Retrieve the webhook secret from your provider's settings and store it in environment variables as WEBHOOK_SECRET
  3. Create a dedicated route handler that accepts POST requests at a path like /webhooks/events
  4. Extract the signature from the webhook request headers (typically X-Signature, X-Hub-Signature-256, or Stripe-Signature)
  5. Extract the raw request body as a string (before JSON parsing) — this is critical for signature verification
  6. Recreate the signature using HMAC-SHA256 with your secret key and the raw body
  7. Use constant-time comparison to verify the calculated signature matches the header signature
  8. Only parse and process the webhook payload if the signature matches; reject unsigned requests with 403 status

Code

const express = require('express');
const crypto = require('crypto');
const app = express();

// Store raw body as string for signature verification
app.use(express.raw({ type: 'application/json' }));

// Webhook signature verification middleware
function verifyWebhookSignature(req, res, next) {
  const signature = req.headers['x-webhook-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  if (!signature || !secret) {
    return res.status(401).json({ error: 'Missing signature or secret' });
  }

  // Get raw body as string
  const rawBody = req.body.toString('utf8');

  // Calculate expected signature using HMAC-SHA256
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(rawBody)
    .digest('hex');

  // Use constant-time comparison to prevent timing attacks
  const isValid = crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );

  if (!isValid) {
    return res.status(403).json({ error: 'Invalid signature' });
  }

  // Attach parsed JSON to request object for next handler
  req.webhook = JSON.parse(rawBody);
  next();
}

// Webhook endpoint
app.post('/webhooks/events', verifyWebhookSignature, (req, res) => {
  const event = req.webhook;

  console.log(`Received webhook event: ${event.type}`);

  // Handle different event types
  switch (event.type)

Note: this example was truncated in the source. See the GitHub repo for the latest full version.

Common Pitfalls

  • Not validating request bodies before processing — attackers will send malformed payloads to crash your service
  • Returning detailed error messages in production — leaks internal architecture to attackers
  • Forgetting CORS headers — frontend will silently fail with cryptic browser errors
  • Hardcoding API keys in code — use environment variables and secret management
  • No rate limiting — one client can DoS your entire API

When NOT to Use This Skill

  • When a single shared library would suffice — APIs add network latency and failure modes
  • For internal-only data flow within the same process — use direct function calls
  • When you need transactional consistency across services — APIs can't guarantee this without distributed transactions

How to Verify It Worked

  • Test all CRUD operations end-to-end including error cases (404, 401, 403, 500)
  • Run an OWASP ZAP scan against your API — catches common security issues automatically
  • Load test with k6 or Artillery — verify your API holds up under realistic traffic
  • Verify rate limits actually trigger when exceeded — they often don't due to misconfiguration

Production Considerations

  • Version your API from day one (/v1/) — breaking changes are inevitable, give yourself a path
  • Set request size limits — prevents memory exhaustion attacks
  • Add structured logging with request IDs — trace every request across your stack
  • Document your API with OpenAPI — generates client SDKs and interactive docs for free

Quick Info

Difficultyintermediate
Version1.0.0
AuthorClaude Skills Hub
apiwebhookssecurity

Install command:

curl -o ~/.claude/skills/webhook-handler.md https://claude-skills-hub.vercel.app/skills/api/webhook-handler.md

Related API Development Skills

Other Claude Code skills in the same category — free to download.

Want a API Development skill personalized to YOUR project?

This is a generic skill that works for everyone. Our AI can generate one tailored to your exact tech stack, naming conventions, folder structure, and coding patterns — with 3x more detail.