Svix

Official JavaScript/TypeScript client for the Svix webhook delivery API and signature verification.

SDK
npm
v2.9.0
3,463 stars
MIT License

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum. How we score it →
91 /100 Excellent
Development Activity 100
Maintenance 100
Community 64
Maturity 60
Momentum 40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation. How we score it →
72 /100 Good
Architecture 78
Code Quality 85
Innovation 70
Learning Curve 55

svix is the official JavaScript/TypeScript client library for Svix, a webhooks-as-a-service platform that handles deliverability, retries, and security for outgoing webhooks on behalf of API providers. The package wraps the full Svix management API (applications, endpoints, messages, event types, ingest sources, connectors, streaming, and more) behind a single Svix client class, and separately ships a Webhook helper for verifying and signing HMAC-based webhook payloads on the receiving end using the open standardwebhooks scheme.

It is one of nine officially maintained Svix client libraries (alongside Go, Python, Java, Kotlin, Ruby, C#, Rust, and PHP) generated from a shared OpenAPI specification in the same monorepo, so its request/response shapes and behavior stay consistent across languages.

What You Get

  • A Svix client class exposing typed resource clients for applications, endpoints, messages, event types, message attempts, ingest sources/endpoints, connectors, integrations, and streaming
  • Automatic regional API routing (US/EU/IN/CA/AU) inferred from the auth token, with an override via serverUrl
  • Built-in retry with exponential backoff (or a custom retry schedule) and automatic idempotency-key generation for POST requests
  • A Webhook class for verifying inbound webhook signatures (svix-* or standard webhook-* headers) and signing outbound payloads
  • Typed error handling via ApiException<HttpErrorOut> / ApiException<HTTPValidationError> so 4xx/422 responses are structured, not opaque
  • An AutoConfig/AutoConfigConsumer helper for auto-discovering endpoint configuration

Common Use Cases

  • Adding outbound webhooks to a SaaS product without building retry/delivery/security infrastructure in-house
  • Verifying that an incoming webhook request actually came from Svix (or another standardwebhooks-compliant sender) before processing it
  • Managing per-tenant application, endpoint, and event-type configuration programmatically from a backend service
  • Building an internal dashboard or CLI on top of the Svix management API for support/ops teams
  • Ingesting third-party webhooks (Shopify, Stripe, GitHub, etc.) through Svix’s ingest sources and republishing them to internal consumers

Under The Hood

Architecture

The JS/TS client lives under javascript/ in the svix-webhooks monorepo. Its entry point, src/index.ts, exports a Svix class that lazily instantiates one resource client per API area (Application, Authentication, BackgroundTask, Connector, Endpoint, Environment, EventType, Health, Ingest, Integration, Message, MessageAttempt, OperationalWebhook, Statistics, Streaming) via getters, each sharing one SvixRequestContext built in request.ts. Every request flows through a single SvixRequest builder (path/query/header/body setters) whose send() performs the fetch call, injects an auto-generated idempotency key for POSTs, retries with exponential backoff via sendWithRetry, and maps error responses through filterResponseForErrors into typed ApiExceptions. Nearly all of src/api/* and src/models/* carry a // this file is @generated header, produced by the monorepo’s shared codegen/ generator from one OpenAPI spec (codegen/lib-openapi.json) that also drives the other eight language SDKs — the genuinely hand-written surface is limited to request.ts, webhook.ts, autoconfig.ts/autoconfigConsumer.ts, and util.ts. Changing the shared SvixRequestContext/SvixRequest abstraction would ripple through every generated api/* file at once, since they all funnel through request.send().

Tech Stack

The package is a TypeScript, ESM-only build (type: module, engines.node >= 22) bundled with tsdown (a Rolldown-based bundler) into dist/index.mjs, linted and formatted with Biome 2.2.4 rather than ESLint/Prettier, and typechecked with tsc --noEmit under a strict tsconfig.json. Its only runtime dependency is standardwebhooks (also maintained by Svix), which webhook.ts wraps to normalize both svix-* and generic webhook-* header names. Dev dependencies (@stablelib/utf8, fast-sha256, mockttp) are used purely for test fixtures and HTTP mocking; there is no web framework in play since this is a pure fetch-based API client.

Code Quality

Tests run on Node’s built-in node:test runner with assert/strict rather than Jest or Vitest. webhook.test.ts (205 lines) exhaustively covers signature-verification edge cases — empty/undefined keys, missing headers, timestamp tolerance, multiple signature values, and both branded and unbranded header formats — alongside autoconfig.test.ts, request.test.ts, and mockttp.test.ts for HTTP-level behavior. CI (javascript-lint.yml) runs Biome checks, tsc typechecking, a build step, a guard that fails if package.json drifts from a fresh build, and the full test suite on every PR touching javascript/** or the shared OpenAPI spec. Errors are typed and explicit (ApiException<T> discriminated by HTTP status) rather than silently swallowed, and setQueryParam includes an exhaustiveness (never) check for type safety.

API Design The surface is deliberately low-friction: new Svix(token) infers the correct regional API host directly from the token’s embedded region segment, so callers on the EU/IN/CA/AU clusters don’t need to configure a base URL manually. Resource access reads naturally (svix.application.create(...), svix.endpoint.list(...)), retries and idempotency keys are handled transparently, and Webhook.verify() accepts either Svix’s own headers or the generic standardwebhooks header names so consumers of either convention integrate without translation code. Getting started is two lines end-to-end, and the same request/response shapes are generated identically across all nine officially supported language clients, which keeps cross-language migration low-cost for teams using more than one.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers