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.
Workload and what breaks
Failure modes
Duplicate deliveries and slow downstream calls cause time-outs unless you design idempotency and async handoff.
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 checks “temporarily”.
Doing database writes synchronously before returning 200 OK.
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
API keys or custom schemes per ingress.
Tracing
See which stage failed—verify, enqueue, or apply.
Tenant routing
Map hosts or prefixes when each customer has a 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 → route → async flow
Gateway sends body as a string; parse JSON after verify. Store provider event IDs before mutating state.
// provider -> gateway route -> fast 200 -> job/pipeline -> apply export async function handler(event) { const evt = JSON.parse(event.body || '{}'); if (await alreadyHandled(evt.id)) { return { statusCode: 200, body: 'duplicate' }; } await handle(evt); return { statusCode: 200, body: 'ok' }; }
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.