Skip to content

Webhooks

Receive events from external services (GitHub, GitLab, Stripe, etc.) and react with AI agents, notifications, or tool executions.

External Service ──POST──▶ /api/webhooks/:path ──▶ Hook Manager ──▶ Action
(HMAC verified) (match by path)
  1. An external service sends an HTTP POST to https://<your-domain>/api/webhooks/<path>
  2. The webhook endpoint verifies the HMAC-SHA256 signature against the hook’s webhookSecret
  3. All hooks with matching webhookPath are triggered
  4. Each hook’s action runs — spawn an agent, send a notification, call another webhook, etc.
  5. If notifyOwner: true is set on a spawn_agent action, the agent’s output is automatically sent to the owner’s linked channels (Telegram, Slack, etc.)

The assistant backend must be reachable from the internet. Options:

  • Cloudflare Tunnel (recommended) — add an ingress rule in your tunnel config:

    cloudflare/config.yml
    ingress:
    - hostname: app.your-domain.com
    service: http://localhost:3005

    Then add a CNAME DNS record: app<tunnel-id>.cfargotunnel.com (proxied).

  • ngrok — quick dev setup: ngrok http 3005

  • Reverse proxy — nginx/caddy with TLS termination pointing to port 3005

If you want Octipus to notify you about webhook events:

  1. Link your Telegram/Slack account in Settings → Channels (or via the /link command)
  2. Verify the binding — the channel must show as “verified” in your user profile
  3. Set notifyOwner: true in the hook’s action config

Generate a random secret for HMAC signature verification:

Terminal window
openssl rand -hex 20

Both sides (Octipus hook and the external service) must share this secret. Never skip this — hooks without a webhookSecret are rejected with 401.

  1. Create the Hook

    Via API:

    Terminal window
    curl -X POST http://localhost:3005/api/hooks \
    -H "Authorization: Bearer <token>" \
    -H "Content-Type: application/json" \
    -d '{
    "name": "GitHub Notifications",
    "trigger": "webhook",
    "triggerConfig": {
    "webhookPath": "github",
    "webhookSecret": "<your-secret>"
    },
    "action": "spawn_agent",
    "actionConfig": {
    "agentPrompt": "A GitHub webhook event was received. Analyze the payload and produce a concise summary.",
    "agentTopic": "communication",
    "orchestrated": false,
    "notifyOwner": true
    }
    }'

    Or use the Hooks page in the web UI.

  2. Configure GitHub

    Terminal window
    gh api repos/OWNER/REPO/hooks -X POST --input - <<'EOF'
    {
    "name": "web",
    "active": true,
    "events": ["pull_request", "issues", "push"],
    "config": {
    "url": "https://app.your-domain.com/api/webhooks/github",
    "content_type": "json",
    "secret": "<your-secret>",
    "insecure_ssl": "0"
    }
    }
    EOF
  3. Verify

    GitHub sends a ping event immediately after creating the webhook. Check the Hooks → Execution Log in the web UI, or:

    Terminal window
    # GitHub delivery history
    gh api repos/OWNER/REPO/hooks/<hook-id>/deliveries \
    --jq '.[0] | "\(.event) → \(.status_code)"'
    # Octipus execution log
    curl http://localhost:3005/api/hooks/<hook-id>/executions \
    -H "Authorization: Bearer <token>" | jq '.executions[0]'
  1. Create the Hook

    Same as GitHub, but use a different webhookPath:

    {
    "triggerConfig": {
    "webhookPath": "gitlab",
    "webhookSecret": "<your-secret>"
    }
    }
  2. Configure GitLab

    1. Go to project Settings → Webhooks
    2. URL: https://app.your-domain.com/api/webhooks/gitlab
    3. Secret token: your webhook secret
    4. Triggers: Push events, Merge request events, etc.

Any service that sends JSON POST requests with HMAC-SHA256 signatures works out of the box.

The sender must include an X-Hub-Signature-256 header:

X-Hub-Signature-256: sha256=<hex-encoded HMAC-SHA256 of raw request body>
Terminal window
PAYLOAD='{"event": "deploy", "status": "success"}'
SECRET="your-webhook-secret"
SIG="sha256=$(echo -n "$PAYLOAD" | openssl dgst -sha256 -hmac "$SECRET" | awk '{print $2}')"
curl -X POST https://app.your-domain.com/api/webhooks/deploy \
-H "Content-Type: application/json" \
-H "X-Hub-Signature-256: $SIG" \
-d "$PAYLOAD"

Best for events that need interpretation before notification.

{
"action": "spawn_agent",
"actionConfig": {
"agentPrompt": "Analyze this deployment event and summarize.",
"agentTopic": "devops",
"orchestrated": false,
"notifyOwner": true
}
}
  • orchestrated: false — spawns a single agent directly (faster)
  • orchestrated: true — routes through the orchestrator for role classification and full tool access
  • notifyOwner: true — sends the agent’s output to all verified channels when done

Best for simple alerts that don’t need AI processing.

{
"action": "notify",
"actionConfig": {
"notifyOwner": true,
"notifyMessage": "Webhook received: &#123;&#123;webhook.body.event&#125;&#125;"
}
}

Forward events to other services.

{
"action": "webhook",
"actionConfig": {
"webhookUrl": "https://other-service.com/api/events",
"webhookMethod": "POST"
}
}

Automated responses like running a git pull or shell command.

{
"action": "execute_tool",
"actionConfig": {
"toolId": "shell",
"toolAction": "execute",
"toolParams": { "command": "cd /app && git pull origin main" }
}
}

When a webhook triggers a spawn_agent action, the payload is automatically appended to the agent prompt:

<your prompt text>
--- Webhook Payload ---
{ "action": "opened", "pull_request": { ... } }
Event type: pull_request

The Event type line is extracted from X-GitHub-Event or X-GitLab-Event headers when present.

You can also use template variables in prompts — see Hooks & Automation for the full list.

  • HMAC-SHA256 required — every webhook hook must have a webhookSecret. Hooks without one reject requests with 401.
  • Signature verification — uses X-Hub-Signature-256 header with timing-safe comparison.
  • Public endpoint/api/webhooks/* is excluded from bearer token auth (it uses HMAC instead).
  • Per-hook secrets — each hook can have a different secret for different services.

Create multiple hooks with different paths for different services:

/api/webhooks/github → GitHub events
/api/webhooks/gitlab → GitLab events
/api/webhooks/stripe → Payment events
/api/webhooks/deploy → CI/CD notifications
/api/webhooks/monitoring → Alerting systems

Each path can have its own secret and action configuration.

ProblemCheck
401 on webhookVerify the secret matches on both sides. Check X-Hub-Signature-256 header is present.
404 on webhookEnsure the URL path matches webhookPath in trigger config.
Hook not firingCheck hook is enabled. Verify webhookPath matches. Look at execution log.
Agent runs but no notificationEnsure notifyOwner: true in action config. Verify channel bindings are verified.
Agent doesn’t see payloadThe payload is auto-appended. Check execution log → trigger context.
502 from tunnelVerify backend is running on port 3005. Check tunnel ingress rule.