django-outbound-webhooks
Outbound webhooks for Django, built on django-domain-events.
Your customers subscribe to domain events, not to your post_save signals. An
endpoint is a row a customer owns: a URL, a secret, the events it wants and the
body format it was integrated against. Delivery is a durable receiver, so
retry, backoff, dead-lettering and replay are inherited rather than rebuilt.
Install
pip install django-outbound-webhooks
Body formats
A customer's endpoint is pinned to one published format version when it registers, and that version is frozen: changing what it renders would change what an already-integrated consumer receives, under a signature that still verifies. A change is a new version.
| Family | Content type | Shape |
|---|---|---|
envelope |
application/json |
id, type, timestamp, and the payload under data |
cloudevents |
application/cloudevents+json; charset=UTF-8 |
CloudEvents 1.0, structured mode |
register_endpoint(
name="Acme production",
url="https://acme.example/hooks/orders",
secret=secret,
event_names=["shop.OrderPlaced"],
# Both optional. Without format_name, DEFAULT_FORMAT decides; without
# format_version, the latest is pinned and that number is written down.
format_name="cloudevents",
)
cloudevents is published only when the deployment says which system produced
the events, because the specification requires a non-empty source and an
invented one would be signed into every body:
DJANGO_OUTBOUND_WEBHOOKS = {"CLOUDEVENTS_SOURCE": "https://shop.example/events"}
Your own format is an object with a name, a version and a render(), which
you publish from your AppConfig.ready():
from django_outbound_webhooks import formats
formats.register(MyFormat())
It does not have to inherit from anything: BodyFormat is a Protocol. The
registry checks at registration that what you handed it can actually render a
delivery, because a format is published once at startup and called hours later
in another process.
Operations
from django_outbound_webhooks import reactivate_endpoint, replay_delivery, rotate_secret
replay_delivery(message_id="018f...") # a new delivery of a logged one
rotate_secret(endpoint, new_secret=secret) # both secrets sign until the window closes
reactivate_endpoint(endpoint) # back on, and the failure count cleared
A replay is a new delivery: a new webhook-id (a receiver deduplicates on
that one), the endpoint's current format and secrets, and its own delivery row,
attempt budget and log rows. It refuses rather than firing something that cannot
arrive - a deleted endpoint, an inactive one, an event retention has pruned.
A rotation overlaps. The specification carries several signatures in one header and a receiver accepts the delivery if any verifies, so the customer deploys the new secret on their own schedule and nothing is dropped in between.
An endpoint that stops answering is switched off after
AUTO_DISABLE_AFTER_DEAD_DELIVERIES consecutive dead deliveries - each of
which has already spent a whole attempt budget across processes and hours, so
the default of twenty is an endpoint that is gone rather than one having a bad
afternoon. A delivery that lands resets the count. Somebody has to tell the
customer, so it fires an event you can receive:
from django_domain_events import receiver
from django_outbound_webhooks.operations.endpoint_disabled import EndpointDisabled
@receiver(EndpointDisabled, key="acme.email_the_customer")
def email_the_customer(disabled: EndpointDisabled) -> None: ...
Status
Released and in use, pre-1.0. Shipped: the registry, signing, delivery with a lease-bounded retry, the request-forgery policy, the delivery log, two body formats, and the operations above. Not yet: the admin surface.
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 django_outbound_webhooks-0.2.0.tar.gz.
File metadata
- Download URL: django_outbound_webhooks-0.2.0.tar.gz
- Upload date:
- Size: 189.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
03cfd959757f7a0f19dd97ebb484de307643152c3e62f5809194a542dd196f6b
|
|
| MD5 |
b161ed08168e5fb0e4341e97af6a9cbc
|
|
| BLAKE2b-256 |
b2b6ecbc8fb96ba34bb2c247901e51eb7dd34ed127985aea2b8871b54ff9301b
|
Provenance
The following attestation bundles were made for django_outbound_webhooks-0.2.0.tar.gz:
Publisher:
release.yml on Artui/django-outbound-webhooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_outbound_webhooks-0.2.0.tar.gz -
Subject digest:
03cfd959757f7a0f19dd97ebb484de307643152c3e62f5809194a542dd196f6b - Sigstore transparency entry: 2828614925
- Sigstore integration time:
-
Permalink:
Artui/django-outbound-webhooks@dd492cfcfdaae4daec383a1d7be55feb4233e4ee -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Artui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dd492cfcfdaae4daec383a1d7be55feb4233e4ee -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_outbound_webhooks-0.2.0-py3-none-any.whl.
File metadata
- Download URL: django_outbound_webhooks-0.2.0-py3-none-any.whl
- Upload date:
- Size: 72.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aea06f2447eaa2768b2d465982503d1c376270aff6fa0c41dd331790f3fd55f1
|
|
| MD5 |
886bdc4d1e2706e3b9db65776b23cc49
|
|
| BLAKE2b-256 |
2bbe783476ab916ac324115545bd573e91bc93fd9c59bae9058e3a8d43567c00
|
Provenance
The following attestation bundles were made for django_outbound_webhooks-0.2.0-py3-none-any.whl:
Publisher:
release.yml on Artui/django-outbound-webhooks
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_outbound_webhooks-0.2.0-py3-none-any.whl -
Subject digest:
aea06f2447eaa2768b2d465982503d1c376270aff6fa0c41dd331790f3fd55f1 - Sigstore transparency entry: 2828614942
- Sigstore integration time:
-
Permalink:
Artui/django-outbound-webhooks@dd492cfcfdaae4daec383a1d7be55feb4233e4ee -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Artui
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@dd492cfcfdaae4daec383a1d7be55feb4233e4ee -
Trigger Event:
push
-
Statement type: