Standard Webhooks (Python)

Python reference implementation for verifying Standard Webhooks HMAC-signed webhook payloads

Library
PyPI
v1.1.0
1,728stars
Apache License 2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
67/100Good
Development Activity72
Maintenance48
Community60
Maturity48
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
78/100Good
Architecture75
Code Quality78
Innovation72
Learning Curve88

Standard Webhooks is an open, community-driven specification for sending and verifying webhooks consistently across providers, and this PyPI package (standardwebhooks) is its official Python reference implementation. It gives webhook consumers a small Webhook class that verifies the webhook-id, webhook-timestamp, and webhook-signature headers against an HMAC-SHA256 signature, protecting against replay and tampering without every provider inventing its own verification scheme.

The specification and its language libraries (Python, JavaScript/TypeScript, Java/Kotlin, Rust, Go, Ruby, PHP, C#, Elixir) live in a single monorepo maintained by the Standard Webhooks project, backed by companies such as Svix, Supabase, and others that have adopted the spec for their own outbound webhooks. The goal is to do for webhook verification what JWT did for API authentication: one well-reviewed protocol implemented consistently everywhere.

What You Get

  • A Webhook class that verifies webhook-id/webhook-timestamp/webhook-signature headers against an HMAC-SHA256 signature derived from the webhook secret
  • Automatic timestamp-freshness checking to reject replayed or excessively old/future webhook deliveries
  • Support for versioned, space-separated multi-signature headers (v1,<sig> v1,<sig>) to allow secret rotation without dropped deliveries
  • A sign() method for producing your own compliant signatures if you are implementing the sending side of the spec
  • Interoperability with reference implementations in JavaScript/TypeScript, Java/Kotlin, Rust, Go, Ruby, PHP, C#, and Elixir, all verifying the same wire format

Common Use Cases

  • Verifying inbound webhooks from any provider (payments, auth, SaaS platforms) that has adopted the Standard Webhooks spec
  • Implementing your own outbound webhook signing so your API’s webhooks are provider-agnostic and verifiable with any Standard Webhooks client
  • Replacing a bespoke, per-provider HMAC verification routine with a single vetted, spec-compliant implementation
  • Rotating webhook signing secrets safely using the spec’s multi-signature header support

Under The Hood

Architecture - The Python package’s entire runtime surface is one class (webhooks.py): Webhook.__init__ decodes a whsec_-prefixed base64 secret, and verify() reconstructs the expected signature by HMAC-SHA256-signing {msg_id}.{timestamp}.{payload}, comparing it (via hmac.compare_digest for constant-time comparison) against each v1,<sig> entry in the space-separated webhook-signature header; a companion __verify_timestamp rejects payloads outside an allowed time window before signature comparison even runs. This mirrors the sibling implementations in libraries/javascript, libraries/java, libraries/rust, etc., all driven by the same spec/standard-webhooks.md document as the single source of truth. Tech Stack - Pure Python 3.6+ standard library only (hashlib, hmac, base64, datetime) with zero runtime dependencies; packaged via classic setuptools/setup.py rather than a modern pyproject-based backend, with mypy --strict and Ruff configured for the wider monorepo. Code Quality - The libraries/python/tests directory exercises signature verification, timestamp edge cases, and malformed-header handling; the package ships a py.typed marker and passes strict mypy, and constant-time comparison is used deliberately for the signature check to avoid timing side-channels. API Design - The public surface is intentionally minimal (construct Webhook(secret), call .verify(payload, headers)), asking developers to make almost no decisions; errors are raised as a single WebhookVerificationError (plus EmptyWebhookSecretError) rather than a sprawling exception hierarchy, keeping integration a two-line change in an existing webhook handler.

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

Search