Webhooks
Huudis fires webhook events to URLs you control so you can react to identity changes in real time — users signing up, joining workspaces, enrolling MFA, granting OIDC consent.
This page is the API reference for webhooks: event envelope, signature recipe, retry policy, full event catalog. For managing subscriptions themselves, see Webhook subscriptions. For the portal walkthrough, see Portal → Webhooks.
Event payload shape
Every webhook is a POST to your endpoint with this body:
{
"id": "evt_01KPG30TXM4N5Q8R1S4T6V8X0Y",
"type": "huudis.user.created.v1",
"createdAt": "2026-05-12T10:42:00.123Z",
"data": {
/* the resource that triggered the event */
}
}
| Field | Notes |
|---|---|
id |
Unique event ID. Use for deduplication on your side. |
type |
huudis.<resource>.<action>.v<n> — versioned, so additive payload changes don't break consumers. |
createdAt |
When the event fired, not when you received it. |
data |
The resource the event is about. Shape depends on type. |
The event ID is stable across retries — idempotently upsert against it.
Headers
Every delivery carries:
Content-Type: application/json
Huudis-Event-Type: huudis.user.created.v1
Huudis-Event-Id: evt_01KPG30TXM4N5Q8R1S4T6V8X0Y
Huudis-Delivery-Id: whdlv_01KPG30TXM…
Huudis-Signature: t=1747033200,v1=8c4a…hexhmac
The signature is HMAC-SHA256 over <t>.<raw-body> with your subscription's secret.
Signature verification
The SDKs ship a one-call helper:
// Node
import { verifyWebhook } from '@forjio/huudis-node/webhooks';
app.post('/webhooks/huudis', (req, res) => {
try {
const event = verifyWebhook(
req.rawBody, // unparsed body bytes
req.headers['huudis-signature'],
process.env.HUUDIS_WEBHOOK_SECRET
);
// event is the parsed payload
res.status(200).end();
} catch {
res.status(401).end();
}
});
# Python
from huudis.webhooks import verify_webhook
event = verify_webhook(req.raw_body, req.headers["huudis-signature"], WEBHOOK_SECRET)
// Go
event, err := huudis.VerifyWebhook(body, r.Header.Get("Huudis-Signature"), secret)
Without the SDK:
- Parse the header.
Huudis-Signature: t=<timestamp>,v1=<hex>. - Construct the signed string:
<timestamp>.<raw-body-bytes>. - Compute
HMAC-SHA256(secret, signed)— compare hex withv1. Use constant-time comparison. - Reject if
now - timestamp > 5 minutes(replay protection).
Retry policy
Failed deliveries (non-2xx, timeout, or your endpoint took longer than 30 seconds) retry with exponential backoff:
| Attempt | Delay since previous |
|---|---|
| 2 | 1 minute |
| 3 | 5 minutes |
| 4 | 30 minutes |
| 5 | 2 hours |
| 6 | 8 hours |
| 7 | 24 hours |
After 7 failed attempts the delivery is failed permanently. Use POST /v1/account/webhook-subscriptions/deliveries/:id/replay to manually retry.
Ordering
Deliveries are not strictly ordered. Retries especially can land after a later event's first attempt. Idempotently process by eventId and consult createdAt if you need happens-before.
Event catalog
Events use the pattern huudis.<resource>.<action>.v<n>. Current types (most reserved-but-not-yet-emitted — see per-event pages):
Users
| Event | When |
|---|---|
huudis.user.created.v1 |
New Huudis user provisioned. |
huudis.user.disabled.v1 |
User globally disabled. |
huudis.user.enabled.v1 |
User re-enabled. |
Sessions
| Event | When |
|---|---|
huudis.session.created.v1 |
New session minted. |
huudis.session.revoked.v1 |
Session or refresh token revoked. |
Workspaces
| Event | When |
|---|---|
huudis.account.created.v1 |
New workspace. |
huudis.account.member_added.v1 |
User joined a workspace. |
huudis.account.service_enabled.v1 |
Workspace opted into a new Forjio product. |
OIDC
| Event | When |
|---|---|
huudis.oidc.consent_granted.v1 |
User consented to an OIDC client for the first time. |
IAM
| Event | When |
|---|---|
huudis.iam.policy_attached.v1 |
Policy attached to a principal. |
The live catalog (with descriptions) is at GET /v1/account/webhook-subscriptions/events/catalog.
Versioning
Event types carry a major version suffix (.v1). Additive changes (new fields, new event types) ship within the same major version. Breaking changes — field removal or renamed fields — bump to .v2. We'd announce a deprecation window of at least 6 months and run both versions in parallel.
Subscribe to the explicit versioned types you handle (huudis.user.created.v1); don't pattern-match on huudis.user.*.
Next
- Webhook subscriptions resource — CRUD on your endpoint registrations.
- Individual event pages in this section.
- SDK overview — the verify-webhook helpers.