Serverless webhook processors for APIs and providers
Stripe, GitHub, Slack, Shopify: run signature verification on the raw body, ack fast before provider timeouts, use async handoff for slow work, design idempotency for duplicate deliveries, and keep traces when retries overlap.
Last updated: 2026-06-28
Answer first
Direct answer
Serverless webhook processors for APIs and providers. Dedicated functions per provider reduce accidental coupling between webhook processors.
When it fits
- SaaS integrations
- Payment providers
- Git hosting events
Tradeoffs
- Skipping signature verification “temporarily” leaves the endpoint open to forged payloads long after the shortcut is forgotten.
- Running database writes synchronously before returning 200 OK invites provider retries—and duplicate records—whenever downstream latency spikes.
Workload and what breaks
Webhook failure modes
Duplicate deliveries and slow downstream calls cause time-outs unless you design idempotency and async handoff from the start.
If you run heavy mutations before returning 2xx, providers will retry—and you will double-charge or double-write unless every path is idempotent.
One overloaded endpoint drags down unrelated user traffic.
Where shortcuts fail
Common shortcuts
Skipping signature verification “temporarily” leaves the endpoint open to forged payloads long after the shortcut is forgotten.
Running database writes synchronously before returning 200 OK invites provider retries—and duplicate records—whenever downstream latency spikes.
How Inquir helps
Webhook architecture: verify, ack fast, then async
Dedicated functions per provider reduce accidental coupling between webhook processors.
Pipelines continue work after a fast HTTP response so provider timeouts never block idempotent writes.
What you get
Webhook gateway tooling: auth, traces, tenant routes
Route-level auth
Enforce API keys or custom auth schemes per ingress route, before handler code runs.
Tracing
Traces show which stage failed—verify, enqueue, or apply—so you debug retries instead of guessing.
Tenant routing
Map hosts or path prefixes cleanly when every customer gets a dedicated webhook URL.
What to do next
How to process webhooks on Inquir Compute
Verify signatures, acknowledge within provider timeouts, apply writes idempotently.
Verify raw request + dedupe event ID
Reject bad signatures and block duplicates before mutating state.
Return success inside timeout window
Acknowledge quickly so providers do not retry unnecessarily.
Enqueue heavy work + apply idempotent writes
Continue asynchronously and keep side effects replay-safe.
Code example
Provider-specific implementation patterns
Real providers have provider-specific headers and timeout constraints. Use separate functions per provider — verification logic stays small and reviewable.
import Stripe from 'stripe'; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); export async function handler(event) { const rawBody = event.body ?? ''; const sig = event.headers['stripe-signature'] ?? ''; let evt; try { evt = stripe.webhooks.constructEvent(rawBody, sig, process.env.STRIPE_WEBHOOK_SECRET); } catch (err) { return { statusCode: 400, body: `Webhook Error: ${err.message}` }; } const isNew = await db.upsertWebhookEvent(evt.id, evt.type); if (!isNew) return { statusCode: 200, body: 'duplicate' }; await global.durable.startNew('process-payment', undefined, { eventId: evt.id, type: evt.type, obj: evt.data.object }); return { statusCode: 200, body: 'ok' }; }
import { createHmac } from 'node:crypto'; export async function handler(event) { const rawBody = event.body ?? ''; const hmac = event.headers['x-shopify-hmac-sha256']; const digest = createHmac('sha256', process.env.SHOPIFY_WEBHOOK_SECRET).update(rawBody).digest('base64'); if (hmac !== digest) return { statusCode: 401, body: 'invalid signature' }; const topic = event.headers['x-shopify-topic']; // e.g. 'orders/create' const order = JSON.parse(rawBody); await global.durable.startNew('process-order', undefined, { topic, orderId: order.id }); return { statusCode: 200, body: '' }; }
When it fits
Good fit
When this works
- SaaS integrations
- Payment providers
- Git hosting events
When to skip it
- Bi-directional sockets—different transport
FAQ
FAQ
Why must the raw body stay untouched for HMAC verification?
Providers sign exact bytes; JSON re-serialization or charset changes alter the payload and cause false “invalid signature” failures.
Should webhooks do heavy work before returning 200?
No—acknowledge within provider timeouts, then continue in a pipeline or background function so retries do not duplicate expensive side effects.
How do I handle duplicate webhook deliveries?
Treat provider event IDs as idempotency keys: persist “seen” before mutating data so at-least-once delivery stays safe.