Sophon Docs
Features

Webhooks

Trigger Sophon from external systems, and subscribe external systems to Sophon events — with HMAC signatures and retry.

Webhooks are how Sophon talks to the outside world asynchronously. They come in two flavors:

  • Inbound — external systems POST to Sophon; an agent or workflow runs in response.
  • Outbound — Sophon POSTs to external systems when events happen (task completed, approval requested, cron fired, …).

Both flavors support HMAC-SHA256 signing, retries with exponential backoff, and per-webhook filters.

Inbound webhooks

An inbound webhook is a URL Sophon exposes. Anything POSTed to it triggers an agent or workflow.

Creating one

Dashboard → Settings → Webhooks → Add Inbound. Configure:

  • Name — internal label
  • Path/api/webhooks/receive/<your-slug> (auto-generated or custom)
  • Action — Agent (send the POST body as a message), Workflow (trigger with the POST body as $trigger.body), or Custom handler
  • Secret — generated; used for HMAC signature verification (optional but recommended)
  • Filters — optional rules on headers or body that must match before the webhook fires (e.g., X-GitHub-Event: push)

Once saved, you get the full URL and secret. Paste them into the external system.

Verifying the signature

On every POST, Sophon computes HMAC_SHA256(secret, body) and compares against the X-Sophon-Signature header. Mismatches are rejected with 401.

import hmac, hashlib, base64

signature = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
# send with header "X-Sophon-Signature: sha256=<signature>"

Many external systems (GitHub, Stripe, Slack) sign their webhooks with their own scheme. Sophon supports the common ones automatically — pick the scheme when you create the webhook.

Example — GitHub push to agent

Create inbound webhook:
  Path:    /api/webhooks/receive/github-push
  Action:  agent "sophon"
  Message: "A push happened: {{$trigger.body.head_commit.message}} on {{$trigger.body.ref}}"
  Scheme:  GitHub (uses X-Hub-Signature-256)
  Secret:  (paste GitHub's secret)
  Filter:  X-GitHub-Event == "push"

In GitHub: add this URL as a webhook with Content-Type: application/json.

Every push to the repo now sends a chat message to Sophon, which processes it and (likely) runs a CI summary or updates memory.

Outbound webhooks

An outbound webhook is a URL Sophon posts to when specific events occur.

Creating one

Dashboard → Settings → Webhooks → Add Outbound. Configure:

  • Name
  • Target URL — where to POST
  • Secret — used to HMAC-sign outbound payloads (recipient verifies)
  • Events — which events to subscribe to (see table below)
  • Filters — optional rules on event payload (e.g., only workflow.completed for workflow morning-briefing)
  • Headers — custom headers added to every POST
  • Retry policy — max attempts, backoff curve

Events

EventFires whenPayload includes
task.queued / .started / .completed / .failedAny task transitionsTask ID, session, agent, status, duration
approval.requested / .approved / .rejected / .timed_outApproval lifecycleApproval ID, tool, params, risk level, outcome
workflow.created / .updated / .deleted / .run.started / .run.completed / .run.failedWorkflow lifecycleWorkflow ID, run ID, duration, error
cron.fired / .failedCron executionJob ID, fire time, duration, outcome
document.uploaded / .deletedDocument lifecycleDocument ID, title, size, tags
memory.written / .forgottenMemory changesEntry ID, content excerpt, scope
discussion.started / .completed / .failedDiscussion lifecycleRun ID, topic, verdict
node.online / .offline / .command.executedSophon Node eventsNode ID, command, result

Retries

Failed outbound POSTs (non-2xx, or no response within timeout) retry with exponential backoff: 1 min, 5 min, 15 min, 1 h, then give up. After giving up, the delivery failure is logged and (optionally) the webhook auto-disables.

You can force a retry from the Dashboard delivery log, or disable auto-disable in per-webhook settings.

Outbound payload format

{
  "event": "task.completed",
  "timestamp": "2026-04-22T10:15:23.000Z",
  "webhookId": "wh_abc123",
  "deliveryId": "del_xyz789",
  "data": {
    "taskId": "task_def456",
    "sessionId": "sess_...",
    "agentId": "sophon",
    "duration": 4321,
    "tokensUsed": 1847,
    "outcome": "completed"
  }
}

The deliveryId is unique per POST attempt; use it for deduplication on your end if you receive retries.

Testing

Dashboard → Settings → Webhooks → <webhook> → Test. Sends a synthetic event with sample data. Your receiver should respond 200 OK; Sophon shows the response status, headers, and body.

For inbound webhooks, the Test button shows the URL to POST to, a sample curl, and live logs of the last 20 incoming requests.

Delivery log

Every delivery attempt is logged:

  • Delivery ID, event, attempt number
  • Request URL, headers, body
  • Response status, headers, body (truncated to 2 KB)
  • Latency, error message if any

Dashboard → Settings → Webhooks → <webhook> → Deliveries. Filter by status (delivered / failed / pending). Retry failed deliveries one at a time or in bulk.

Retention: 30 days on Personal/Pro, configurable on Enterprise.

Security

  • HMAC signing — always use secrets for inbound webhooks. Unsigned webhooks should be reserved for test-only slugs.
  • TLS only — outbound webhooks require HTTPS except for localhost (for dev).
  • SSRF guard — outbound URL targets are checked against the SSRF guard (blocks private networks, cloud metadata).
  • Secret rotation — rotating a secret invalidates the old one immediately; update the external system to avoid failed signature checks.

CLI

sophon webhooks list
sophon webhooks show <id>
sophon webhooks test <id>
sophon webhooks deliveries <id>
sophon webhooks retry <delivery-id>
sophon webhooks rotate-secret <id>

Limits and gotchas

  • Outbound rate limit — max 100 deliveries/minute per Gateway. Over the limit, events queue and eventually drop (24 h buffer).
  • Inbound body size — 5 MB max. Larger payloads return 413.
  • Response timeout — outbound webhooks time out after 10 seconds waiting for response. Long-running handlers should ack immediately and process async.
  • Filter regexes must be safe — no catastrophic backtracking. Sophon pre-validates.

Where to go next