{"@context":"https://schema.org","@graph":[{"@type":"WebPage","@id":"https://inquir.org/serverless-webhook-processor#webpage","url":"https://inquir.org/serverless-webhook-processor","name":"Serverless webhook processor with retries, logs & background jobs","headline":"Serverless webhook processor with retries, logs & background jobs","description":"Serverless webhook processor with HMAC signature verification, fast ACK inside provider timeouts, retry-safe async background jobs, and execution traces—handle Stripe, GitHub, Slack, and any webhook provider on stable URLs you own.","inLanguage":"en-US","isPartOf":{"@id":"https://inquir.org/#website"},"author":{"@type":"Organization","name":"Inquir"},"datePublished":"2025-01-01T00:00:00.000Z","dateModified":"2026-04-20T00:00:00.000Z","citation":"https://inquir.org/docs"},{"@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https://inquir.org"},{"@type":"ListItem","position":2,"name":"Serverless webhook processor","item":"https://inquir.org/serverless-webhook-processor"}]},{"@type":"HowTo","@id":"https://inquir.org/serverless-webhook-processor#howto","name":"Serverless webhook processor with retries, logs & background jobs","description":"Serverless webhook processor with HMAC signature verification, fast ACK inside provider timeouts, retry-safe async background jobs, and execution traces—handle Stripe, GitHub, Slack, and any webhook provider on stable URLs you own.","inLanguage":"en-US","author":{"@type":"Organization","name":"Inquir"},"step":[{"@type":"HowToStep","position":1,"name":"Verify signature on raw body","text":"Read event.body as-is before any JSON.parse. Compute expected HMAC and compare with timing-safe equality to reject forgeries."},{"@type":"HowToStep","position":2,"name":"Write idempotency key, return 200","text":"Upsert the provider event ID before any state mutation. Return 200 within the provider window—Stripe expects < 30s, Slack < 3s."},{"@type":"HowToStep","position":3,"name":"Enqueue slow work to pipeline","text":"For any work that outlasts the timeout window, call global.durable.startNew() and return the job reference. The orchestration retries independently of the HTTP response."}],"isPartOf":{"@id":"https://inquir.org/serverless-webhook-processor#webpage"}},{"@type":"FAQPage","@id":"https://inquir.org/serverless-webhook-processor#faq","url":"https://inquir.org/serverless-webhook-processor","isPartOf":{"@id":"https://inquir.org/serverless-webhook-processor#webpage"},"mainEntity":[{"@type":"Question","name":"Why must I verify before parsing?","acceptedAnswer":{"@type":"Answer","text":"HMAC is computed over the raw bytes as received. If you JSON.parse first and re-serialize, whitespace and key order can differ, causing verification to fail on valid events. Always read event.body as a string before calling any HMAC function."}},{"@type":"Question","name":"How do I handle Slack's 3-second timeout?","acceptedAnswer":{"@type":"Answer","text":"Return immediately with 200 and an empty body. Enqueue the actual work to a pipeline step. If you need to post a response back to Slack, use the responseUrl from the slash-command payload inside the pipeline step."}},{"@type":"Question","name":"What about replay attacks?","acceptedAnswer":{"@type":"Answer","text":"Combine HMAC verification, provider-supplied timestamps (check within ±5 minutes), and idempotency keys so late replays are rejected and duplicate deliveries are no-ops."}},{"@type":"Question","name":"Can I test locally?","acceptedAnswer":{"@type":"Answer","text":"Use the Stripe CLI `stripe listen --forward-to` or similar tools to forward real webhook events to a local handler. Keep the same event.body string contract as the gateway delivers in production."}}]}]}