Claude API Webhook Integration Setup Guide
If you searched for "claude api webhook integration setup," you're probably trying to connect an incoming event — a form submission, a GitHub push, a Stripe payment, a Slack message — to a Claude-powered action, and get the result back out automatically. The thing worth knowing upfront: the Claude API itself does not emit webhooks. It's a synchronous request/response HTTP API — you send a message, you get a completion back (or a stream of chunks). There's no event bus on Anthropic's side that calls your server when something happens.
That means "webhook integration" with Claude almost always refers to one of two patterns you build yourself: (1) an inbound webhook receiver that triggers a Claude API call when an external event arrives, or (2) an outbound callback that notifies another system once Claude has finished generating a response. This guide covers both, with a working setup you can copy.
The two integration patterns
Pattern A — event triggers Claude: Stripe, GitHub, Twilio, or your own app POSTs a webhook to your server. Your server validates it, extracts the relevant data, and calls the Claude API to summarize, classify, draft a reply, or take some action based on that payload.
Pattern B — Claude's output triggers a webhook: A long-running or batch job calls Claude, and once the completion is ready, your server POSTs the result to a callback URL — useful for async pipelines where the original caller doesn't wait on the HTTP connection.
Most real integrations combine both: receive an event, call Claude, send the result onward.
Step 1: Build the webhook receiver
Start with a minimal endpoint that accepts the incoming event and verifies it's genuine before doing anything expensive. Never call an LLM on unverified input from the public internet.
const express = require("express");
const crypto = require("crypto");
const app = express();
app.use(express.raw({ type: "*/*" }));
function verifySignature(req, secret) {
const signature = req.headers["x-webhook-signature"];
const expected = crypto
.createHmac("sha256", secret)
.update(req.body)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expected, "hex")
);
}
app.post("/webhooks/incoming", (req, res) => {
if (!verifySignature(req, process.env.WEBHOOK_SECRET)) {
return res.sendStatus(401);
}
// Acknowledge fast, process async
res.sendStatus(202);
handleEvent(JSON.parse(req.body.toString()));
});
Respond quickly (202 Accepted) and do the Claude call asynchronously. Most webhook providers retry aggressively if you don't respond within a few seconds, and a Claude completion can easily take longer than that — especially with longer prompts or tool use.
Step 2: Queue the work, don't block the request
Put the event on a queue (SQS, Redis, BullMQ, or even a simple in-process job table) rather than calling Claude directly inside the webhook handler. This protects you from:
- Duplicate webhook deliveries (most providers send at-least-once)
- Timeouts cascading back to the sender
- Burst traffic overwhelming your Claude rate limits
async function handleEvent(payload) {
const jobId = payload.id || crypto.randomUUID();
await queue.add("process-with-claude", { jobId, payload });
}
Use the event's own ID as an idempotency key so retried deliveries don't produce duplicate Claude calls and duplicate side effects.
Step 3: Call the Claude API from the worker
The worker picks up the job and makes the actual completion request. If you're routing through SubToAPI instead of managing Anthropic credentials directly, the call looks like this:
const response = await fetch("https://api.subtoapi.app/v1/messages", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.SUBTOAPI_KEY}`,
"Content-Type": "application/json"
},
body: JSON.stringify({
model: "claude-sonnet-4-5",
max_tokens: 1024,
messages: [
{ role: "user", content: `Summarize this event: ${JSON.stringify(payload)}` }
]
})
});
const result = await response.json();
SubToAPI issues per-application sub_live_... keys and tracks usage metadata per key, which matters for webhook-driven workloads: you can see exactly how many tokens a given integration (e.g., "github-pr-summarizer") is consuming without digging through Anthropic's own billing dashboard. Full request/response shape is in /docs/messages.
Step 4: Send the result onward
Once you have the completion, POST it to wherever it needs to go — a Slack incoming webhook, your own callback URL, a database write, or a ticketing system.
await fetch(payload.callbackUrl, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
jobId,
status: "completed",
output: result.content[0].text
})
});
If the downstream system needs to show progress rather than wait for a single blob, consider streaming the Claude response instead of batching it — see /docs/streaming for the SSE event format.
Step 5: Handle failures and retries
Webhook pipelines fail in predictable ways. Build for them from day one:
- Retry with backoff on Claude API errors (rate limits, transient 5xxs) before giving up on a job
- Dead-letter queue for jobs that fail repeatedly, so you can inspect and replay them manually
- Timeouts per job, not per HTTP request — a worker loop shouldn't wait forever on a stuck completion
- Signed outbound callbacks — if you're calling someone else's webhook endpoint, sign your payload the same way you'd want inbound webhooks signed to you
Step 6: Secure the whole chain
- Verify every inbound webhook signature before touching the payload
- Store webhook secrets and API keys in environment variables or a secrets manager, never in code
- Rotate application keys per integration so a leaked key only exposes one pipeline — SubToAPI supports issuing separate
sub_live_keys per app from one account, which keeps a compromised GitHub-bot key from affecting your Slack-bot key - Log request IDs and token usage per job for debugging and cost attribution
Putting it together
A working Claude webhook integration is really three independent pieces: a fast, signature-verified receiver; a queue that decouples receiving from processing; and a worker that calls the Claude API and forwards the result. None of these pieces require anything special from Anthropic's side — they're standard backend patterns applied to an LLM call. If you want the API layer handled for you — key management, usage tracking, streaming — start with /signup, check /docs/quickstart for the first call, and /pricing for plan details.
Questions
Does the Claude API support native webhooks? No. It's a request/response HTTP API with optional streaming. Any webhook behavior — triggering a call or notifying on completion — has to be built on your own server.
Should I call Claude directly inside my webhook handler? No. Acknowledge the webhook quickly, queue the work, and call Claude from a background worker. This avoids timeouts and duplicate processing from retried deliveries.
How do I avoid duplicate Claude calls from retried webhooks? Use the event's own ID (or a hash of its payload) as an idempotency key, and check it against a processed-jobs store before enqueuing or calling the Claude API again.