Skip to main content
INTEGRATION

Webhooks

Subscribe to run, approval, budget, and policy events. HMAC-SHA256 signatures with rotation grace window. Standard delivery semantics — at-least-once, exponential backoff, dead-letter after 8.5 minutes of failures.

Rungate posts webhooks for state changes the operator (or your agent) wants to act on. Subscriptions are configured in the dashboard at app.rungate.dev/webhooks or via the admin API.

Events

EventFires when
run.startedFirst call in a run is dispatched.
run.completedRun closed normally (idle timeout or explicit completion).
run.blockedRun stopped by a budget cap or policy violation.
step.failed_overA call failed over from primary to fallback provider.
approval.pendingTool call hit a gate; awaiting human review.
approval.approvedGate resolved positively.
approval.rejectedGate resolved negatively.
budget.alertRun crossed the 80% alert threshold.
budget.exceededRun exceeded the hard cap.
policy.driftAgent attempted an action outside the policy allowlist.
account.updatedAccount name, email, slug, or status changed.
admin_token.createdNew admin token issued.
agent.createdNew agent created and initial token issued.

Payload shape

Consistent across events:

{
  "event": "approval.pending",
  "delivered_at": "2026-04-26T14:12:20Z",
  "data": {
    "gate_id": "gate_8xk2m",
    "run_id": "run_customer_refund_2026_04_26",
    "agent_id": "agt_claude_code_prod",
    "rule": "refund:over-$500",
    "proposed_action": {
      "tool": "issue_refund",
      "args": { "amount_usd": 1240.00 }
    },
    "expires_at": "2026-04-26T15:48:12Z"
  }
}

Per-event data shapes are documented in the OpenAPI spec under the WebhookPayload* schemas.

Signature verification

Every delivery carries an HMAC-SHA256 signature over the raw request body, with a timestamp to prevent replay. Verify before trusting any payload.

X-Rungate-Timestamp: 1737126732
X-Rungate-Signature: v1=1e4b0f...    # current secret
X-Rungate-Signature: v1=9c3a87...    # previous secret (rotation grace)

Two signatures may be present during a rotation grace window so you can roll the signing secret without dropped deliveries. Accept if either signature matches.

Verification (Python)

import hmac, hashlib

def verify(body: bytes, timestamp: str, signatures: list[str], secret: str) -> bool:
    signed = timestamp.encode() + b"." + body
    expected = "v1=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    return any(hmac.compare_digest(expected, sig) for sig in signatures)

Verification (TypeScript)

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

function verify(body: Buffer, timestamp: string, signatures: string[], secret: string): boolean {
  const signed = Buffer.concat([Buffer.from(timestamp + '.'), body]);
  const expected = 'v1=' + createHmac('sha256', secret).update(signed).digest('hex');
  const expectedBuf = Buffer.from(expected);
  return signatures.some((sig) => {
    const sigBuf = Buffer.from(sig);
    return sigBuf.length === expectedBuf.length && timingSafeEqual(sigBuf, expectedBuf);
  });
}

Reject stale timestamps (more than 5 minutes old) to prevent replay attacks even if a signature leaks.

Delivery semantics

  • At-least-once. Webhooks may deliver more than once. Make your handler idempotent — key off data.run_id + event + delivered_at for deduplication.
  • Retries. On 4xx/5xx responses or timeouts, Rungate retries with exponential backoff for up to ~8.5 minutes total before marking the delivery dead-letter. Dead-letter events surface in the dashboard.
  • 2xx response. Any 2xx is success. Empty body is fine.
  • 4xx terminal. Specific 4xx codes (400, 401, 403, 404, 410, 422) are treated as terminal — Rungate stops retrying. Use this if you want to deliberately drop deliveries (return 410 from a decommissioned endpoint).
  • Timeout. 10 seconds per delivery attempt.

Rotating the signing secret

From the dashboard or admin API, rotate the secret. Rungate signs new deliveries with the new secret AND the previous secret for a grace window (default 24 hours), so your verifier can update without dropped deliveries:

  1. Rotate the secret. Both signatures now appear in headers.
  2. Update your verifier to use the new secret.
  3. After the grace window ends, only the new signature is sent.

Common patterns

Slack notification on approval gates

Subscribe to approval.pending. On receipt, post into a Slack channel with approve/reject buttons that call back to your handler. Your handler hits Rungate's POST /api/approval-requests/{id}/approve (or /reject).

PagerDuty on dead-letter

Subscribe to budget.exceeded + run.blocked in production. Page on either event firing for a critical agent.

Audit log

Subscribe to all events. Dump payloads to your existing audit pipeline (BigQuery, Snowflake, S3 + Athena). Run-level grouping is preserved by data.run_id.