← Blog

Claude API Webhook Signature Verification Guide

2026-10-18 · 5 min read · SubToAPI Team

Does the Claude API even use webhooks?

If you landed here searching for "claude api webhook signature verification," the short answer is: Anthropic's Messages API doesn't send webhooks. It's a synchronous request/response HTTP API — you send a prompt, you get a completion (or a stream of tokens). There's no event system where Anthropic pushes notifications to a URL you control, so there's no "Claude webhook secret" to verify against.

What you're almost certainly trying to solve is one of two real problems: (1) you're receiving webhooks from a third-party service — Stripe, GitHub, Slack, a payment processor, a CRM — and want to verify those are genuine before triggering a Claude API call in response, or (2) you're building your own async layer on top of Claude (queue a job, call Claude, notify a client via webhook when it's done) and need to sign and verify those outgoing notifications yourself. Both are solvable with the same standard HMAC pattern. Let's walk through it.

The standard webhook signature pattern

Nearly every webhook system (Stripe, GitHub, Slack, Shopify) uses the same shape:

  1. The sender computes an HMAC-SHA256 hash of the raw request body using a shared secret.
  2. The signature (and often a timestamp) is sent in a header, e.g. X-Signature or Stripe-Signature.
  3. Your server recomputes the hash on the raw body it received and compares it to the header value using a constant-time comparison.
  4. If they match and the timestamp is recent, the request is trusted.

The two most common mistakes: verifying against a body that's already been parsed/re-serialized by a framework (which changes whitespace and breaks the hash), and skipping replay protection so an old captured request can be resent indefinitely.

Verifying an incoming webhook before calling Claude

Here's a generic Express handler that verifies a signed webhook and only then calls Claude to process the payload — a common pattern for "when X happens, ask Claude to summarize/classify/respond":

import express from "express";
import crypto from "crypto";

const app = express();

// Capture the raw body — do NOT use express.json() here
app.use("/webhooks/incoming", express.raw({ type: "application/json" }));

app.post("/webhooks/incoming", async (req, res) => {
  const signature = req.headers["x-signature"];
  const timestamp = req.headers["x-timestamp"];
  const secret = process.env.WEBHOOK_SECRET;

  const expected = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${req.body}`)
    .digest("hex");

  const valid =
    signature &&
    crypto.timingSafeEqual(
      Buffer.from(signature),
      Buffer.from(expected)
    );

  if (!valid) return res.status(401).send("invalid signature");

  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) {
    return res.status(401).send("stale timestamp");
  }

  const event = JSON.parse(req.body);
  // Signature verified — safe to act on this event
  res.status(200).send("ok");
  processEventWithClaude(event); // fire-and-forget, don't block the ack
});

Key details:

Signing your own outgoing webhooks for async Claude jobs

If you're the one notifying a client after a long-running Claude task (document analysis, agentic tool-use chains, batch summarization), sign the payload the same way so your clients can verify it came from you:

function signPayload(payload, secret) {
  const timestamp = Math.floor(Date.now() / 1000);
  const body = JSON.stringify(payload);
  const signature = crypto
    .createHmac("sha256", secret)
    .update(`${timestamp}.${body}`)
    .digest("hex");

  return { body, headers: { "X-Signature": signature, "X-Timestamp": timestamp } };
}

Each client gets its own secret, generated at onboarding and rotatable from your dashboard. Store secrets hashed at rest if you can, and never log raw payloads that include them.

Where SubToAPI fits into this

The Claude call itself — the part that happens after you've verified a signature and decided to act — still needs an API key, rate limiting, and usage visibility, especially if multiple webhook sources are hitting the same Claude backend. SubToAPI turns your Claude access into a standard HTTPS API with sub_live_... keys, so your webhook handler just makes a normal authenticated request:

curl https://api.subtoapi.app/v1/messages \
  -H "Authorization: Bearer $SUBTOAPI_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "claude-sonnet-4-5",
    "max_tokens": 1024,
    "messages": [{"role": "user", "content": "Summarize this webhook payload"}]
  }'

Because every key has its own usage metadata, you can tell exactly which webhook integration is driving Claude spend — useful when you've got Stripe, GitHub, and a support-ticket webhook all triggering Claude calls under one project. Streaming and tool use work the same way as the standard Messages API, so you don't change how you call Claude, only how you authenticate it. See the quickstart, messages, streaming, and tool use docs, and check pricing if you're consolidating several Claude-backed services onto one key system. Start with a free trial at signup.

Security checklist for webhook handlers that call Claude

questions

Does Anthropic's Claude API send webhooks I need to verify? No. The Messages API is synchronous request/response. If you're verifying a signature, it's from a third-party webhook source or your own async notification system, not from Anthropic directly.

What's the safest way to compare webhook signatures? Use a constant-time comparison function like Node's crypto.timingSafeEqual, and always compute the hash over the raw request body before any JSON parsing or middleware touches it.

Can I use the same signing pattern for my own Claude-powered webhook notifications? Yes — HMAC-SHA256 over the payload plus a timestamp, sent in custom headers, is the standard approach used by Stripe, GitHub, and Shopify, and it works just as well for notifying clients when an async Claude job finishes.

Turn your Claude access into an HTTPS API

SubToAPI gives you application API keys, streaming, tool use and usage insights on top of your existing Claude access — set up in minutes.

Start free  Read the quickstart →