Webhooks.

Outbound delivery for things you should not have to poll for, with retries and a dispatcher you can see the state of.

What they are for

Pulling a TAXII collection on a timer is right for bulk intel. It is wrong for “tell me the moment an advisory that affects me is published”. Webhooks cover the second case.

Delivery

A pending event is written to the database first, then a dedicated webhook-dispatcher worker POSTs it to your endpoint. Because the event is persisted before the attempt, a dispatcher restart does not lose events.

  • Retries use exponential backoff rather than a fixed interval.
  • Attempt count and last error are recorded per delivery.
  • Delivery is at-least-once — your handler should be idempotent.
event occursadvisory sentpersist pendingbefore any attemptdispatcher POSTsyour endpoint2xx · doneretryEXPONENTIAL BACKOFFat-least-once delivery — make your handler idempotent
Fig. The event is persisted before the first attempt, so a dispatcher restart cannot lose it.

Advisory channels

Advisories fan out over up to three channels per subscribed tenant: portal (an in-app notification, delivered immediately), email, and webhook. Each is recorded as its own delivery row so partial success is visible.

Email and webhook are dispatcher-dependent

The portal channel is written synchronously when an advisory is sent, so an in-app notification appears at once. email and webhook rows are left pending for the dispatcher. If that worker is not running, those two channels stay pending indefinitely and the advisory looks sent from the portal's point of view.

Subscriptions

Managed under /v1/webhooks. A tenant chooses which channels it wants and a minimum severity, so a subscription can be scoped to “only critical” without filtering on your side.

Webhooks — OmniIntel docs · OmniIntel