Webhooks quickstart
From nothing to a verified delivery. You will register a receiving endpoint, publish an event to it, and check the signature on the webhook that arrives.
You need an admin-scoped API key. Keys look like whsk_… and are issued when your workspace is provisioned; the product overview covers how to get one.
Every path below is relative to https://webhooks.nimbusnexus.net.
1. Register an endpoint
An endpoint is the HTTPS URL we deliver to, plus the subscriptions that decide which event types it receives. This one takes everything beginning with order.:
curl -sX POST https://webhooks.nimbusnexus.net/v1/endpoints \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://your-app.example/webhooks",
"subscriptions": [{"match_kind": "prefix", "pattern": "order."}]
}'
The response carries the endpoint and its signing secret:
{
"id": "ep_3f9a…",
"url": "https://your-app.example/webhooks",
"status": "enabled",
"health": "healthy",
"subscriptions": [{ "match_kind": "prefix", "pattern": "order." }],
"secret": "whsec_…"
}
The secret is shown once. Store it in your secrets manager now — it is what you verify deliveries against, and it cannot be read back. If you lose it, rotate it and update your handler.
match_kind accepts exact, prefix, suffix, or all. Start narrow: an all subscription on a receiver that only understands two event types means writing a filter in your handler that the subscription could have done for you.
2. Publish an event
curl -sX POST https://webhooks.nimbusnexus.net/v1/events \
-H "Authorization: Bearer $ADMIN_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-123-created" \
-d '{
"event_type": "order.created",
"payload": {"order_id": "ord_123", "total": 4200}
}'
The field is event_type, not type — type is the field name inside the delivered envelope, which is a different object. Sending type here is a 422.
The response tells you what the publish produced:
{
"event_uid": "evt_7c21…",
"event_type": "order.created",
"deliveries_created": 1
}
deliveries_created: 0 is the answer to the most common first-run surprise — it means nothing was subscribed to that type, not that the publish failed. Check the endpoint's subscription pattern against the type you sent.
The Idempotency-Key header is what makes the publish safe to retry: replaying the same key returns the original event instead of fanning out again.
3. Verify the delivery
The webhook arrives at your URL as a POST. Verify it before doing any work — an unverified handler will process anything that finds your URL.
import hashlib, hmac, time
def handle(request):
secret = ENDPOINT_SIGNING_SECRET # from step 1
timestamp = request.headers["X-Webhook-Timestamp"]
signature = request.headers["X-Webhook-Signature"]
raw_body = request.body # RAW bytes — never re-serialize the JSON
# 1. Reject anything outside the replay window.
if abs(int(time.time()) - int(timestamp)) > 300:
return Response(status_code=400)
# 2. Recompute and compare in constant time. The header carries one token normally, but
# several comma-separated ones during a secret rotation — accept if ANY matches.
expected = "sha256=" + hmac.new(
secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
).hexdigest()
if not any(hmac.compare_digest(expected, t.strip()) for t in signature.split(",")):
return Response(status_code=400)
# 3. Only now is the payload trustworthy.
process(request.json())
return Response(status_code=200) # 2xx = delivered; anything else retries
Signing the raw bytes rather than a re-encoded object is the detail that trips people up: parsing and re-serializing JSON reorders keys and changes whitespace, and the signature is over the bytes we sent. Read the body once, keep it, verify, then parse.
The full contract — every header, and why each rule exists — is in Signature verification. The SDKs ship a verify helper that implements all of it, which is the recommended route.
4. Confirm it landed
curl -s "https://webhooks.nimbusnexus.net/v1/deliveries?status=dead" \
-H "Authorization: Bearer $ADMIN_KEY"
An empty items array means nothing has exhausted its retries. If your handler was down during step 2, the delivery will be here — fix the handler, then replay it:
curl -sX POST https://webhooks.nimbusnexus.net/v1/deliveries/dlv_456/redeliver \
-H "Authorization: Bearer $ADMIN_KEY"
What's next
- Signature verification — the complete signing contract.
- SDKs — skip the hand-rolled HMAC.
- CLI — the same operations without curl.
- Webhooks (product) — objects, delivery semantics, and idempotency.