Webhooks.

Get a POST to your URL whenever a turn lands in the review queue or gains a signal. Connect AgentLoop to Slack, Discord, PagerDuty, or your own systems for real-time alerting.

Configure

Set up your endpoint URL and signing secret in the dashboard's Webhooks page. Each webhook has a unique URL, a signing secret shown once at creation, and a list of events it subscribes to.

Where to configure

Sign in to app.getagentloop.io and go to Webhooks in the sidebar. Admin role required.

Events

Payload

Every event has the same envelope. The data block contains the turn.

json
{
  "id": "evt_01h9...",
  "event": "turn.signal_received",
  "created_at": "2026-04-26T18:42:13.482Z",
  "api_version": "2026-04-26",
  "org_id": "org_abc",
  "delivery": { "id": "whd_...", "attempt": 1, "webhook_id": "wh_..." },
  "data": {
    "turn": {
      "id": "turn_abc",
      "question": "What's the Pix limit at night?",
      "agent_response": "...",
      "user_id": "u_42",
      "signals": { "thumbs_down": true },
      "duplicate_count": 1,
      "tags": [],
      "model": "gpt-4o",
      "dashboard_url": "https://app.getagentloop.io/review?turn_id=turn_abc"
    },
    "new_signals": ["thumbs_down"]
  }
}

Verify the signature

Every request includes X-AgentLoop-Signature: t=<unix>,v1=<hex>. Reject requests whose signature doesn't match — anyone with your URL could otherwise post fake events to it.

python · flask
import hmac, hashlib, time
SECRET = "whsec_..."  # the secret shown once when you created the webhook

@app.post("/webhook/agentloop")
def receive():
    raw = request.get_data(as_text=True)
    header = request.headers.get("X-AgentLoop-Signature", "")
    parts = dict(p.split("=", 1) for p in header.split(","))
    ts, v1 = int(parts["t"]), parts["v1"]
    if abs(time.time() - ts) > 300:
        return "stale", 400
    expected = hmac.new(
        SECRET.encode(), f"{ts}.{raw}".encode(), hashlib.sha256
    ).hexdigest()
    if not hmac.compare_digest(v1, expected):
        return "bad signature", 403
    # ... process the event
    return "", 200

Custom headers

Some webhook receivers require an API key in a specific header (e.g. apikey for Digibee, x-api-key for AWS API Gateway, Authorization for bearer-token schemes). Configure these on each webhook — up to 5 custom headers per webhook, sent verbatim on every delivery.

Reserved names like Content-Type, User-Agent, and X-AgentLoop-* cannot be set (we manage those ourselves).

Retries

We retry up to 5 times with exponential backoff (10s, 20s, 40s, 80s, 160s) on transient failures (5xx, timeouts, network errors). 4xx responses (except 408 / 429) stop retrying immediately — they suggest a permanent misconfiguration. Every attempt is recorded in the delivery log; you can manually resend any past delivery from the dashboard.