AO

Webhook notifier

Generic HTTP POST. Retries, exponential backoff, custom headers.

Slot: notifier · Name: webhook
macOSSupported
LinuxSupported
WindowsSupported

Point it at any HTTPS endpoint. AO POSTs a JSON event. Use this for PagerDuty-style integrations, custom dashboards, or anything we don't have a dedicated notifier for.

Use

agent-orchestrator.yaml
notifier:
  - type: webhook
    url: https://example.com/ao-events
    headers:
      Authorization: "Bearer ${MY_TOKEN}"
      X-Source: "agent-orchestrator"
    retries: 5                  # default 3
    retryDelayMs: 2000          # default 1000

Config

KeyRequiredDefaultWhat it does
urlHTTPS endpoint that accepts POST
headersoptional{}Custom request headers (supports ${ENV_VAR} interpolation)
retriesoptional3Retry count on 429/5xx/network errors
retryDelayMsoptional1000Base retry delay (exponential backoff)

Payload

Envelope

Every POST has a type discriminant. Most events use notification:

{
  "type": "notification",
  "event": {
    "id": "3f6a1b2c-...",
    "type": "pr.created",
    "priority": "info",
    "sessionId": "sess_01HXY...",
    "projectId": "myproject",
    "timestamp": "2026-04-17T15:00:00.000Z",
    "message": "PR opened: fix(auth): handle token expiry",
    "data": {}
  }
}

When actions are attached (e.g. approve/retry buttons in supported notifiers):

{
  "type": "notification_with_actions",
  "event": { "...": "same fields as above" },
  "actions": [
    { "label": "View PR", "url": "https://github.com/owner/repo/pull/123" }
  ]
}

Free-form messages sent via ao send arrive as:

{
  "type": "message",
  "message": "Hello from AO",
  "context": {}
}

Event types

event.typeDefault priorityWhen emitted
session.spawnedinfoSession created
session.workinginfoAgent begins working on the issue
session.exitedinfoAgent process exited cleanly
session.killedinfoSession was manually killed
session.idleinfoAgent has been idle for a while
session.stuckurgentAgent appears stuck (no activity)
session.needs_inputurgentAgent is blocked waiting for user input
session.erroredurgentAgent hit an unrecoverable error
pr.createdinfoPR opened by the agent
pr.updatedinfoPR updated (new commits pushed)
pr.mergedactionPR was merged
pr.closedinfoPR was closed without merging
ci.passinginfoCI checks passed
ci.failingwarningCI checks failed
ci.fix_sentinfoAgent sent a CI fix to itself
ci.fix_failedwarningAgent's CI fix attempt failed
review.pendinginfoPR review requested
review.approvedactionPR approved by reviewer
review.changes_requestedwarningReviewer requested changes
review.comments_sentinfoReview comments sent to agent
review.comments_unresolvedinfoAgent left unresolved review comments
automated_review.foundwarningAutomated review tool (e.g. BugBot) left comments
automated_review.fix_sentinfoAgent sent fixes for automated review comments
merge.readyactionPR is approved + CI green — ready to merge
merge.conflictswarningMerge conflicts detected
merge.completedactionPR was successfully merged
reaction.triggeredinfoA configured reaction was triggered
reaction.escalatedurgentA reaction was escalated to a human notifier
summary.all_completeinfoAll sessions in the project completed

Signature verification

The webhook notifier does not sign outgoing requests. There is no X-Signature or HMAC header added to POSTs. To secure your endpoint:

  • Use a secret Authorization header (set via headers.Authorization in config, passed as ${MY_TOKEN}).
  • Restrict inbound traffic to your AO host via IP allowlist or VPN.
  • Use a reverse proxy with mutual TLS if needed.

Why use this over a specific notifier

  • You want a single endpoint regardless of Slack/Discord/email routing (handled downstream).
  • You're building an internal AO dashboard of your own.
  • You want structured events for observability tooling (Datadog, Honeycomb, etc.).