Webhooks

Receive signed HTTPS notifications when a budget is crossed, an invoice is issued, a request is refused by policy or a key is revoked.

3 min read Updated View as Markdown Report a problem

Webhooks tell your systems when something happens in your organization. Every delivery is signed, retried on failure and recorded in a delivery log.

Open Admin → Webhooks. You need the Edit the organization’s profile permission (admin:org).

Adding an endpoint

Choose Add endpoint and enter:

  • an HTTPS URL. On the hosted service it must be a public address on port 443; a self-hosted installation can deliver to any port;
  • a description;
  • the events to send.

The endpoint’s signing secret is shown once. Store it with your receiver. An organization can have up to 20 endpoints.

Events

EventWhen
budget.threshold_crossedA budget first passes 50, 80 or 90% of its limit in a period
budget.exhaustedA budget reaches 100% of its limit; requests against it are refused
billing.invoice_createdA monthly invoice is issued
billing.invoice_paidAn invoice is paid
billing.payment_failedA payment attempt fails
billing.state_changedSavings switch between active and pass-through
governance.guardrail_blockedPrompt injection screening blocks a prompt
governance.dlp_blockedData loss prevention blocks or masks a request
governance.model_access_deniedA caller asks for a model it may not use
governance.rate_limit_exceededA caller exceeds a rate limit
security.api_key_createdA key is created or rotated in
security.api_key_revokedA key is revoked, deleted, or removed with its member
security.member_invitedSomeone is invited (hosted) or added (self-hosted)
security.member_removedA member is removed
security.sso_connection_changedA single sign-on connection is created, changed or deleted
webhook.pingSend test on an endpoint

The four governance.* events are sent at most once a minute for each caller and rule; every refusal is still on the Activity page. No event contains prompt text, a detected value or a secret.

What your receiver gets

One POST per event and endpoint:

POST /your/webhook HTTP/1.1
Content-Type: application/json
User-Agent: acog-webhooks/1
Acog-Event: budget.threshold_crossed
Acog-Delivery: whd_8Kd2…
Acog-Signature: t=1792161166,v1=5f0c3a…

{"id": "whev_3xQ…", "type": "budget.threshold_crossed", "created_at": "2026-10-16T14:32:18Z",
 "data": {"scope": "org", "pool_id": "…", "window": "month", "pct": 80, "used_usd": 4000, "limit_usd": 5000}}

id identifies the event and is the same on every attempt and every endpoint. Acog-Delivery identifies this event’s delivery to this endpoint and is the same on every retry: use either to ignore duplicates.

Verifying the signature

Acog-Signature carries a timestamp t and v1, the hex HMAC-SHA256 of "<t>.<raw body>" keyed with the endpoint’s secret.

import hashlib, hmac, time

def verify(secret: str, header: str, raw_body: bytes, tolerance: int = 300) -> bool:
    parts = dict(item.split("=", 1) for item in header.split(","))
    timestamp, signature = parts["t"], parts["v1"]
    if abs(time.time() - int(timestamp)) > tolerance:
        return False
    expected = hmac.new(secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, signature)

Verify against the raw body exactly as received, compare in constant time, and reject a timestamp more than five minutes from now.

Responding and retries

Answer with any 2xx status within 10 seconds, then do the work. Anything else is a failure, including a redirect (redirects are not followed).

  • A failed delivery is retried after 1 minute, 5 minutes, 30 minutes, 2 hours, 6 hours, 12 hours and 24 hours.
  • After 50 consecutive failures the endpoint is switched off; the console says why.
  • A delivery still undelivered after 3 days is given up.
  • Delivery is at least once and events are not ordered.

Events that happen while an endpoint is switched off are not queued for it.

Managing an endpoint

Open an endpoint to see its delivery log (every attempt and its payload, kept 30 days), change its events, switch it off or on, rotate its secret (the old secret stops working immediately) or send a test.