Matchers & Helpers
Filter, detect, and parse webhook requests with built-in matchers for method, header, and body matching. Includes provider detection helpers and JSON body parsing.
Updated Mar 2026
Matchers
Matchers are predicate functions that return (request) => boolean. Use them with waitFor, waitForAll, and subscribe to filter incoming requests by method, headers, path, body content, and more.
import {
matchMethod,
matchHeader,
matchPath,
matchQueryParam,
matchBodyPath,
matchBodySubset,
matchContentType,
matchAll,
matchAny,
} from "@webhooks-cc/sdk";matchMethod
Match by HTTP method. Comparison is case-insensitive.
matchMethod(method: string): (request: Request) => booleanconst req = await client.requests.waitFor(slug, {
match: matchMethod("POST"),
});matchHeader
Match by header presence, or by header name and exact value. Header names are matched case-insensitively. Values are matched with exact (case-sensitive) equality.
matchHeader(name: string, value?: string): (request: Request) => boolean// Header exists (any value)
matchHeader("stripe-signature");
// Header exists with exact value
matchHeader("x-github-event", "push");matchPath
Match request paths using glob-style wildcards. * matches a single path segment, ** matches multiple segments.
matchPath(pattern: string): (request: Request) => booleanmatchPath("/webhooks/*"); // matches /webhooks/stripe, not /webhooks/stripe/events
matchPath("/webhooks/**"); // matches /webhooks/stripe/events/123
matchPath("/api/*/webhooks"); // matches /api/v1/webhooksmatchQueryParam
Match query parameter presence or a specific value.
matchQueryParam(key: string, value?: string): (request: Request) => boolean// Parameter exists (any value)
matchQueryParam("token");
// Parameter exists with exact value
matchQueryParam("token", "abc123");matchBodyPath
Match a value at a dot-notation path into the parsed JSON body. Supports array indexing with numeric path segments.
matchBodyPath(path: string, value: unknown): (request: Request) => booleanmatchBodyPath("type", "checkout.session.completed");
matchBodyPath("data.object.id", "obj_123");
matchBodyPath("items.0.name", "Widget");matchBodySubset
Deep partial match against the parsed JSON body. Returns true if every key/value in the subset exists in the body, recursively.
matchBodySubset(subset: Record<string, unknown>): (request: Request) => booleanmatchBodySubset({
type: "checkout.session.completed",
data: { object: { status: "complete" } },
});matchContentType
Match the Content-Type header, ignoring charset and other parameters.
matchContentType(type: string): (request: Request) => booleanmatchContentType("application/json");
// matches "application/json; charset=utf-8"matchAll
Logical AND -- returns true only when every matcher matches. Requires at least one matcher.
matchAll(...matchers: Array<(request: Request) => boolean>): (request: Request) => booleanmatchAll(matchMethod("POST"), matchHeader("content-type", "application/json"));matchAny
Logical OR -- returns true when at least one matcher matches. Requires at least one matcher.
matchAny(...matchers: Array<(request: Request) => boolean>): (request: Request) => booleanmatchAny(matchMethod("PUT"), matchMethod("PATCH"));Combining matchers
Compose matchers to build precise filters for waitFor:
const req = await client.requests.waitFor(slug, {
timeout: "10s",
match: matchAll(
matchMethod("POST"),
matchHeader("stripe-signature"),
matchBodyPath("type", "checkout.session.completed")
),
});Nest matchAll and matchAny for complex logic:
const req = await client.requests.waitFor(slug, {
timeout: "30s",
match: matchAll(
matchMethod("POST"),
matchAny(matchBodyPath("type", "invoice.paid"), matchBodyPath("type", "invoice.payment_failed"))
),
});Provider detection
Detector functions return true or false based on the presence of provider-specific headers. Use them to route captured requests by provider.
import {
isStripeWebhook,
isGitHubWebhook,
isShopifyWebhook,
isSlackWebhook,
isTwilioWebhook,
isPaddleWebhook,
isLinearWebhook,
isDiscordWebhook,
isStandardWebhook,
} from "@webhooks-cc/sdk";| Function | Header(s) checked |
|---|---|
isStripeWebhook(request) | stripe-signature |
isGitHubWebhook(request) | x-github-event |
isShopifyWebhook(request) | x-shopify-hmac-sha256 |
isSlackWebhook(request) | x-slack-signature |
isTwilioWebhook(request) | x-twilio-signature |
isPaddleWebhook(request) | paddle-signature |
isLinearWebhook(request) | linear-signature |
isDiscordWebhook(request) | x-signature-ed25519 AND x-signature-timestamp |
isStandardWebhook(request) | webhook-id AND webhook-timestamp AND webhook-signature |
All header comparisons are case-insensitive. Discord and Standard Webhooks require multiple headers to be present simultaneously.
Router example
const request = await client.requests.waitFor(slug, { timeout: "10s" });
if (isStripeWebhook(request)) {
// Verify Stripe signature and handle event
} else if (isGitHubWebhook(request)) {
// Verify GitHub signature and handle event
} else if (isStandardWebhook(request)) {
// Standard Webhooks request (Polar, Svix, Clerk, Resend)
} else {
console.log("Unknown provider");
}Body parsing
Four utilities for extracting structured data from captured request bodies.
import { parseJsonBody, parseFormBody, parseBody, extractJsonField } from "@webhooks-cc/sdk";parseJsonBody
Safely parse a JSON request body. Returns undefined if the body is empty or not valid JSON. Never throws.
parseJsonBody(request: Request): unknown | undefinedconst body = parseJsonBody(request);
if (body) {
console.log(body);
}parseFormBody
Parse an application/x-www-form-urlencoded body. Returns undefined if the content type does not match. Repeated keys are collected into arrays.
parseFormBody(request: Request): Record<string, string | string[]> | undefinedconst form = parseFormBody(request);
if (form) {
console.log(form.email); // "[email protected]"
console.log(form.tags); // ["a", "b"] if repeated
}parseBody
Auto-detect content type and parse accordingly. JSON and form-encoded bodies are decoded; other content types are returned as raw text.
parseBody(request: Request): unknown | Record<string, string | string[]> | string | undefinedconst parsed = parseBody(request);extractJsonField
Extract a nested field from the JSON body using dot-notation. Supports array indexing. Returns undefined if the body is missing, invalid JSON, or the path does not exist.
extractJsonField<T>(request: Request, path: string): T | undefinedconst email = extractJsonField<string>(request, "data.customer.email");
const firstItem = extractJsonField<string>(request, "items.0.name");matchJsonField
A convenience matcher that checks whether a top-level JSON field equals an expected value. Works like matchBodyPath but limited to top-level fields.
import { matchJsonField } from "@webhooks-cc/sdk";
const req = await client.requests.waitFor(slug, {
match: matchJsonField("type", "checkout.session.completed"),
});Learn more
API Reference
Complete method reference for the SDK.
Signature Verification
Verify webhook signatures for 13 providers.
Testing
CI/CD integration and testing patterns.