Skip to main content
Outbound webhooks let your systems react the moment OpenQuota produces a new earning or changes a deal’s state. They’re signed with HMAC-SHA256 so you can verify the request came from us and hasn’t been tampered with.

Subscription

Subscriptions are managed in the OpenQuota admin UI (Settings → Webhooks). Each subscription has:
  • URL — where we POST events.
  • Events — the event names this subscription is interested in. See below.
  • Secret — shown once at creation. Use it to verify signatures. Lost secrets mean rotate the subscription.

Events

EventFires when
earning.createdA new earning row is written by the engine, typically following a deal event.
Additional event types are planned; the admin UI is the source of truth for what’s currently shippable.

Payload

{
  "event": "earning.created",
  "delivered_at": "2026-04-22T10:15:30.000Z",
  "data": {
    "domain_event_id": "dom_api_...",
    "deal_id": "deal_api_org_...",
    "source": "api",
    "earnings_written": 2,
    "recalcs": 1
  }
}

Verifying the signature

Every POST carries a X-OpenQuota-Signature header of the form sha256=<hex>. Compute:
HMAC-SHA256(secret, raw_body_bytes)
and compare hex-encoded. Use a constant-time comparison.

Node / Bun

import { createHmac, timingSafeEqual } from "node:crypto";

function verify(rawBody: string, header: string, secret: string): boolean {
  const expected = createHmac("sha256", secret)
    .update(rawBody)
    .digest("hex");
  const received = header.replace(/^sha256=/, "");
  const a = Buffer.from(expected, "hex");
  const b = Buffer.from(received, "hex");
  return a.length === b.length && timingSafeEqual(a, b);
}

Retry semantics

Failed deliveries (non-2xx or timeout) retry with exponential backoff: 1s, 5s, 25s, 125s, 625s. After 5 failed attempts the delivery is marked dead and visible in the admin UI; it’s your responsibility to fix your endpoint and use the Replay button to redeliver.

Idempotency

Each delivery has a unique X-OpenQuota-Delivery-Id. Use it to deduplicate on your side — the same event may be redelivered on retry or manual replay.

Disabling a subscription

Toggle active: false in the admin UI. Existing queued deliveries drain; no new deliveries are queued until you re-enable.