Documentation
Ship webhook monitoring in a single commit
Install the SDK, wrap your handler, and you're watching traffic in under 60 seconds. Pick your language below.
Installation
Install the Outworx Hooks SDK using your preferred package manager.
npm install outworx-hooksyarn add outworx-hookspnpm add outworx-hooksQuick Start
Wrap your existing webhook handler with the Outworx monitoring layer. Choose your language and framework below.
// app/api/webhooks/stripe/route.ts
import { init } from 'outworx-hooks';
import { withWebhookMonitoring } from 'outworx-hooks/nextjs';
init({ apiKey: process.env.OUTWORX_HOOKS_API_KEY! });
export const POST = withWebhookMonitoring(
{ provider: 'stripe' },
async (req) => {
const body = await req.json();
// handle webhook event
return Response.json({ received: true });
}
);Configuration
Configure the SDK with your API key and optional settings. Your API key is verified with Outworx on first use — invalid or unknown keys are rejected, so make sure to register to get a valid key.
import { init } from 'outworx-hooks';
init({
// Required: your Outworx API key
apiKey: process.env.OUTWORX_HOOKS_API_KEY!,
// Optional: custom endpoint (for self-hosted / enterprise)
endpoint: 'https://ingest.outworx.io',
// Optional: enable debug logging
debug: false,
// Optional: timeout for telemetry sends (ms)
timeout: 5000,
// Optional: error callback for failed ingest attempts
// onError: (err) => console.error(err),
});Track Options
Customize tracking per handler with these options.
withWebhookMonitoring({
// Required: identify the webhook provider
provider: 'stripe',
// Optional: override how event_type is derived
eventTypeHeader: 'stripe-event-type',
eventTypeField: 'type',
// Optional: capture the full request + response bodies
// (off by default — payloads often contain customer data)
captureBody: true,
// Optional: capture request headers (on by default; sensitive
// values like Authorization / Cookie are always redacted)
captureHeaders: true,
// Optional: custom metadata attached to every event
metadata: {
environment: 'production',
service: 'billing',
},
}, handler);| Option | Type | Default | Description |
|---|---|---|---|
| provider | string | required | Webhook provider name (stripe, shopify, github, etc.) |
| eventTypeHeader | string | auto | Header name to extract event_type from. Auto-detected for known providers. |
| eventTypeField | string | auto | Body field to extract event_type from (e.g., "type" for Stripe). |
| captureBody | boolean | false | Capture request + response bodies. Off by default — payloads often contain customer PII. |
| captureHeaders | boolean | true | Capture request headers. Sensitive values (Authorization, Cookie, etc.) are always redacted. |
| metadata | object | {} | Custom key-value pairs attached to every event. |
Signature Verification
The SDK verifies webhook signatures for you — just pass the signing secret. Supports Stripe, GitHub, Shopify, Svix, Clerk, and Slack. Invalid signatures are rejected with 401 before your handler runs, and every verification result is reported to your dashboard for audit.
import { init } from 'outworx-hooks';
import { withWebhookMonitoring } from 'outworx-hooks/nextjs';
init({ apiKey: process.env.OUTWORX_HOOKS_API_KEY! });
export const POST = withWebhookMonitoring(
{
provider: 'stripe',
signatureSecret: process.env.STRIPE_WEBHOOK_SECRET!,
// Optional:
// rejectInvalidSignatures: false, // default true — set false to let handler decide
// signatureTolerance: 300, // default 300s — replay-attack window
},
async (req) => {
// Signature is already verified — handle the event
const body = await req.json();
return Response.json({ received: true });
}
);Custom verifier
For providers we don't support natively, pass your own function:
withWebhookMonitoring(
{
provider: 'my-service',
signatureVerifier: async (rawBody, headers) => {
return myCheck(rawBody, headers['x-my-signature']);
},
},
handler
);Standalone helpers
Import and use the verifiers directly:
import { verifyStripeSignature } from 'outworx-hooks/security';
const valid = verifyStripeSignature({
rawBody,
header: req.headers['stripe-signature'] as string,
secret: process.env.STRIPE_WEBHOOK_SECRET!,
});express.json({ verify }) or the fastify-raw-body plugin. See the SDK README for setup examples.Idempotency
Webhook providers retry deliveries when your handler times out or returns a non-2xx response — which can cause double-charged customers, duplicate emails, and double-provisioned resources. Pass an idempotencyKey function and the SDK short-circuits retries with the cached response from the first successful delivery.
import { init } from 'outworx-hooks';
import { withWebhookMonitoring } from 'outworx-hooks/nextjs';
init({ apiKey: process.env.OUTWORX_HOOKS_API_KEY! });
export const POST = withWebhookMonitoring(
{
provider: 'stripe',
signatureSecret: process.env.STRIPE_WEBHOOK_SECRET!,
// Dedupe on the Stripe event ID. Retries of the same event will
// return the cached response without re-invoking the handler.
idempotencyKey: (_req, body) => (body as any).id,
// Optional: cache window (default 24h, max 7d)
// idempotencyTtl: 3600,
},
async (req) => {
const event = await req.json();
await chargeCustomer(event);
return Response.json({ received: true });
}
);Recommended keys per provider
// Stripe — event ID in the body
idempotencyKey: (_req, body) => (body as any).id
// GitHub — delivery ID header
idempotencyKey: (_req, _body, headers) => headers['x-github-delivery']
// Shopify — webhook ID header
idempotencyKey: (_req, _body, headers) => headers['x-shopify-webhook-id']
// Svix / Clerk — message ID header
idempotencyKey: (_req, _body, headers) => headers['svix-id']Environment Variables
The SDK supports configuration via environment variables as an alternative to the init function. Works the same for both JavaScript and Python.
# Required
OUTWORX_HOOKS_API_KEY=ohk_your_api_key_here
# Optional
OUTWORX_HOOKS_ENDPOINT=https://ingest.outworx.io
OUTWORX_HOOKS_DEBUG=false
OUTWORX_HOOKS_CAPTURE_PAYLOADS=false
OUTWORX_HOOKS_TIMEOUT=5000When using environment variables, you can initialize without arguments:
// No init() call needed — the SDK reads
// OUTWORX_HOOKS_API_KEY from your environment
// automatically when your handler runs.