Skip to content

Testing

Use the SDK in your test suite to verify webhook integrations end-to-end. Create temporary endpoints, trigger your application, and assert on the captured requests.

Updated Mar 2026

Pattern: test, assert, cleanup

import { WebhooksCC } from "@webhooks-cc/sdk";
import { describe, it, expect, beforeAll, afterAll } from "vitest";
 
const client = new WebhooksCC({
  apiKey: process.env.WHK_API_KEY!,
});
 
describe("payment webhooks", () => {
  let endpoint: Awaited<ReturnType<typeof client.endpoints.create>>;
 
  beforeAll(async () => {
    endpoint = await client.endpoints.create({
      name: "test-payments",
    });
  });
 
  afterAll(async () => {
    await client.endpoints.delete(endpoint.slug);
  });
 
  it("sends a webhook on successful payment", async () => {
    // Trigger your application with the endpoint URL
    await processPayment({
      webhookUrl: endpoint.url,
      amount: 4999,
    });
 
    // Wait for the webhook to arrive
    const request = await client.requests.waitFor(endpoint.slug, {
      timeout: 5000,
      match: (r) => r.method === "POST",
    });
 
    const body = JSON.parse(request.body!);
    expect(body.event).toBe("payment.success");
    expect(body.amount).toBe(4999);
  });
});

CI/CD integration

Add your API key as a secret in your CI environment. Example GitHub Actions config:

# .github/workflows/test.yml
env:
  WHK_API_KEY: ${{ secrets.WHK_API_KEY }}
 
steps:
  - uses: actions/checkout@v4
  - run: npm ci
  - run: npm test

Using waitFor

The SDK includes a built-in waitFor method that polls until a matching request arrives:

// Wait for any request
const req = await client.requests.waitFor(endpoint.slug);
 
// Wait for a POST with a specific body
const req = await client.requests.waitFor(endpoint.slug, {
  timeout: 10000,
  pollInterval: 500,
  match: (r) => {
    if (r.method !== "POST") return false;
    const body = JSON.parse(r.body ?? "{}");
    return body.event === "order.created";
  },
});

Testing localhost webhook handlers

Use sendTo to send signed webhooks directly to your local server. No webhooks.cc endpoint needed — the request goes straight to localhost with proper provider signatures.

import { WebhooksCC } from "@webhooks-cc/sdk";
 
const client = new WebhooksCC({ apiKey: process.env.WHK_API_KEY! });
 
it("handles Polar subscription webhook", async () => {
  const res = await client.sendTo("http://localhost:3000/api/webhooks/polar", {
    provider: "standard-webhooks",
    secret: process.env.POLAR_WEBHOOK_SECRET!,
    body: {
      type: "subscription.created",
      data: {
        id: "sub_test_123",
        status: "active",
        customer: { email: "[email protected]" },
      },
    },
  });
 
  expect(res.status).toBe(200);
});

Works with all providers: standard-webhooks (Polar, Svix, Clerk, Resend), stripe, github, shopify, twilio.

Testing utilities

The SDK provides testing helpers via the @webhooks-cc/sdk/testing subpath export:

import { withEndpoint, captureDuring, assertRequest } from "@webhooks-cc/sdk/testing";
 
// Auto-cleanup wrapper — endpoint is deleted when callback completes
const result = await withEndpoint(client, async (endpoint) => {
  await triggerWebhook(endpoint.url);
  return client.requests.waitFor(endpoint.slug, { timeout: "10s" });
});
 
// Capture requests during an async action
const requests = await captureDuring(
  client,
  async (endpoint) => {
    await triggerMultipleWebhooks(endpoint.url);
  },
  { count: 3, timeout: "15s" }
);
 
// Structured assertion with diff output
const result = assertRequest(request, {
  method: "POST",
  bodyJson: { event: "payment.success" },
});
expect(result.pass).toBe(true);

Tips

  • Use unique endpoint names per test run to avoid conflicts in parallel CI
  • Always clean up endpoints in afterAll / afterEach
  • The free plan supports 50 requests/day — enough for most test suites

Framework examples

Standard Webhooks + Vitest

Polar, Svix, Clerk, Resend with sendTo.

Stripe + Vitest

Payment webhook assertions.

GitHub + Jest

Push event verification.

Polar.sh + Playwright

Subscription lifecycle E2E testing.

Playwright E2E

Browser flow + webhook assertions.