Fasthook is a webhook framework for FastAPI Applications
Project description
🪝 Fastapihooks
Fastapihooks is a high-performance, and pluggable webhook management system for FastAPI. It allows you to "webhook-enable" any router with a single decorator, offloading the heavy lifting to a scalable sidecar worker while keeping your API response times near zero.
📚 Documentation
- Full multi-page docs: docs/index.md
✨ Key Features
-
⚡ Zero-Impact Emission: Uses FastAPI BackgroundTasks to ensure webhook processing never slows down your API flow.
-
🔌 Backend by Design, Extensions by You: Fastapihooks ships with
BackgroundTaskBackendonly. Build Redis/Kafka/SQS backends by implementingBaseBackend. -
🛠️ Sidecar Worker: A dedicated async engine designed for high-concurrency delivery with built-in retries and HMAC signing.
-
🛡️ Secure by Default: Optional HMAC-SHA256 signing — when a
signing_secretis provided, every delivery includes a verifiableX-Fastapihooks-Signatureheader. -
📊 Observable: Telemetry support (Logfire, OpenTelemetry, Prometheus) planned for a future release.
-
📝 Type-Safe: Powered by Pydantic for flexible payload transformations.
Quick Start
- Install
pip install fastapihooks
- Configure
from contextlib import asynccontextmanager from fastapi import FastAPI, BackgroundTasks, Request from fastapihooks import Fastapihooks from fastapihooks.backends import BackgroundTaskBackend hooks = Fastapihooks(backend=BackgroundTaskBackend(signing_secret="your-secret")) @asynccontextmanager async def lifespan(app: FastAPI): async with hooks: # closes HTTP connections on shutdown yield app = FastAPI(lifespan=lifespan) @app.post("/orders") @hooks.hook("order.created") async def create_order(request: Request, background_tasks: BackgroundTasks): # Your business logic here return {"id": "ord_123", "status": "confirmed"}
- Run the Worker (The Sidecar)
# Not required for BackgroundTaskBackend; dispatch runs in FastAPI BackgroundTasks. # Use the sidecar only when you implement a queue backend with consume()/ack(). fastapihooks start --backend-module myapp.backends:custom_backend --store-module myapp.stores:store --signing-secret "your-secret"
Advanced Capabilities
Flexible Transformations
Don't just dump your API response. Use the FastapihooksContext to shape exactly what your subscribers see.
def my_transformer(ctx: FastapihooksContext):
return {
"event": ctx.event_name,
"order_id": ctx.response_payload["id"],
"user_agent": ctx.headers.get("user-agent")
}
@app.post("/orders")
@hooks.hook("order.created", transform=my_transformer, include_headers=True)
async def create_order(...):
...
include_request=Truecaveat — When FastAPI parses a Pydantic model parameter (e.g.body: OrderIn), it consumes the request body before your handler runs. After that,await request.body()returns empty bytes andctx.request_payloadwill beb"". Useinclude_request=Trueonly when you inject the rawRequestand read the body yourself. If you only need request headers, preferinclude_headers=True— that is always safe.
Pluggable Architecture
| Component | Responsibility | Available Drivers |
|---|---|---|
| Backend | Transport Layer | BackgroundTaskBackend (Built-in), custom via BaseBackend |
| Store | Subscription Data | SQLStore (PostgreSQL, MySQL, SQLite via SQLAlchemy), MemoryStore (dev/testing), custom via BaseStore |
| Telemetry | Observability | Planned — Logfire, OpenTelemetry, Prometheus |
Custom Store Contract
Use BaseStore to bring your own subscription storage — MongoDB, DynamoDB, Redis, or anything else.
from collections.abc import Iterable
from typing import Any, Literal
from fastapihooks.stores import BaseStore, StoredWebhookSubscription
class MyMongoStore(BaseStore):
async def add_subscription(self, event_name, target_url, auth_type="none", auth_value=None, metadata=None) -> str:
... # insert and return generated ID
async def remove_subscription(self, subscription_id: str) -> bool:
... # delete by ID, return True if found
async def get_subscriptions(self, event_name: str) -> Iterable[StoredWebhookSubscription]:
... # query by event_name
async def update_subscription(self, subscription_id, target_url=None, auth_type=None, auth_value=None, metadata=None) -> bool:
... # partial update, return True if found
Custom Backend Contract
Use BaseBackend to add your own transport backend while keeping the main library lightweight.
from typing import Any
from fastapihooks.backends import BaseBackend
from fastapihooks.stores.base_store import WebhookSubscription
class MyQueueBackend(BaseBackend):
async def publish(
self,
event_name: str,
payload: Any,
owner_id: str | None,
subscribers: list[WebhookSubscription] | None = None,
):
# enqueue event to your transport
...
async def consume(self):
# yield queued events for worker mode
...
async def ack(self, event_id: str):
# ack successful processing
...
Scalability Design
Fastapihooks is designed for horizontal scale. By using an asynchronous backend (eg: Redis Stream Backend), you can run multiple sidecar workers in a Consumer Group. This allows you to process millions of webhooks across a cluster of workers without duplicate deliveries.
Security: HMAC Verification
Fastapihooks signs every payload. Your users can verify the authenticity of a webhook using the X-Fastapihooks-Signature header.
The header value is formatted as sha256=<hex-digest>, matching the convention used by GitHub, Stripe, and most webhook providers.
import hashlib
import hmac
def verify_signature(payload: bytes, secret: str, header: str) -> bool:
algorithm, _, received = header.partition("=")
expected = hmac.new(secret.encode(), payload, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, received)
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fastapihooks-0.1.0.tar.gz.
File metadata
- Download URL: fastapihooks-0.1.0.tar.gz
- Upload date:
- Size: 29.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c3e7f61a77ccfe416e419a5c024c8b76e68378318e344301e9219387b5cc6d1d
|
|
| MD5 |
57f16828cce2a8f8f7eea2db5c15c46c
|
|
| BLAKE2b-256 |
32ae1f5c1da6059027cdb3983003488f984e3a3f09646338849de2acdeeb2fe4
|
Provenance
The following attestation bundles were made for fastapihooks-0.1.0.tar.gz:
Publisher:
publish.yml on iudeen/fastapihooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapihooks-0.1.0.tar.gz -
Subject digest:
c3e7f61a77ccfe416e419a5c024c8b76e68378318e344301e9219387b5cc6d1d - Sigstore transparency entry: 1626281524
- Sigstore integration time:
-
Permalink:
iudeen/fastapihooks@a9a0e39f47a0e2eff49141ef288df61bca018d0b -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/iudeen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a9a0e39f47a0e2eff49141ef288df61bca018d0b -
Trigger Event:
release
-
Statement type:
File details
Details for the file fastapihooks-0.1.0-py3-none-any.whl.
File metadata
- Download URL: fastapihooks-0.1.0-py3-none-any.whl
- Upload date:
- Size: 20.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3eb62b37ed0e5fbe883a5b3ba770eab92eb7118b2dfcf1bae7adcc751b911c4b
|
|
| MD5 |
a263d4db2549c31ec7b002c2a2bf38cb
|
|
| BLAKE2b-256 |
2822fe43ea3b82b6ad620880292f6242759e11a564d0d5c5c6f33967f911ba0b
|
Provenance
The following attestation bundles were made for fastapihooks-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on iudeen/fastapihooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fastapihooks-0.1.0-py3-none-any.whl -
Subject digest:
3eb62b37ed0e5fbe883a5b3ba770eab92eb7118b2dfcf1bae7adcc751b911c4b - Sigstore transparency entry: 1626281535
- Sigstore integration time:
-
Permalink:
iudeen/fastapihooks@a9a0e39f47a0e2eff49141ef288df61bca018d0b -
Branch / Tag:
refs/tags/0.1.0 - Owner: https://github.com/iudeen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@a9a0e39f47a0e2eff49141ef288df61bca018d0b -
Trigger Event:
release
-
Statement type: