Integration
Webhooks
Outbound delivery on sign-off and other lifecycle events.
Webhook service
Configured
Live
DATABRIDGE_WEBHOOK_URL is set — outbound events will be POSTed to the configured receiver.
Events
What we emit
Lifecycle events triggered by gateway and audit workflows.
submission.signoff— HESA submission signed off by an approver.submission.gateway_uploaded— submission uploaded to the HESA gateway.submission.rejected— submission rejected by the gateway or by an approver.
Configuration
Environment variables
Configure the outbound receiver and HMAC secret at boot.
DATABRIDGE_WEBHOOK_URL— receiver endpoint (Slack, Teams, ServiceNow, custom).DATABRIDGE_WEBHOOK_SECRET— shared secret used to sign each payload.- Signature header:
X-DATABRIDGE-SIGNATURE— HMAC-SHA-256 of the JSON body. Verify withverifyWebhookSignature()from@databridge/webhook-delivery.
Delivery
Retry & dead-letter
How we handle transport failures.
- Each delivery is attempted once via
fetchwith a 10-second timeout. - Non-2xx responses and network errors mark the delivery as
delivered: falseand the attempt is kept in the in-memory history for inspection. - When no URL is configured deliveries are queued (stub transport) so demos and tests run without an outbound receiver.
Delivery history 4 events
| Event | Tenant / UKPRN | Occurred | Destination | Signature | Status |
|---|---|---|---|---|---|
| submission.signoff | fhe (UKPRN 10009999) | 5/12/2026, 2:00:05 PM | https://hooks.fhe.ac.uk/databridge | sha256=4f1c9b2e8… | delivered |
| submission.gateway_uploaded | fhe (UKPRN 10009999) | 5/30/2026, 4:00:12 PM | https://hooks.fhe.ac.uk/databridge | sha256=4f1c9b2e8… | delivered |
| submission.signoff | fhe (UKPRN 10009999) | 5/25/2026, 4:20:02 PM | https://hooks.fhe.ac.uk/databridge | sha256=4f1c9b2e8… | delivered |
| submission.rejected | fhe (UKPRN 10009999) | 6/2/2026, 12:00:30 PM | https://hooks.fhe.ac.uk/databridge | sha256=4f1c9b2e8… | queued |
Verify a delivery on the receiver
Compute
HMAC-SHA-256 of the raw JSON body with your shared secret. Compare to the X-DATABRIDGE-SIGNATURE header on the request. Use the constant-time comparison helper in your runtime — never ==.HMAC-SHA-256
import hmac, hashlib
def verify(raw_body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header)
# Flask example
# @app.post("/webhooks/databridge")
# def receive():
# if not verify(request.get_data(), request.headers.get("X-DATABRIDGE-SIGNATURE", ""), SECRET):
# abort(401)
# ...