Featured

Run your Hermes agent on Hostinger, fully managed logoRun your Hermes agent on Hostinger, fully managed

Launch Hermes on Hostinger in one click, fully managed, no VPS knowledge needed. Use code ZACAARON10 for 10% off.

Launch on Hostinger
Deploy OpenClaw in 60 seconds — 20% off logoDeploy OpenClaw in 60 seconds — 20% off

Launch OpenClaw on Hostinger in about 60 seconds and keep your agent live 24/7. Our referral link gives you 20% off, no coupon code needed.

Launch on Hostinger
Crawl and scrape any site into clean data, 10% off logoCrawl and scrape any site into clean data, 10% off

Firecrawl crawls and scrapes any site into clean markdown for your agent. Get 1,000 free credits, and new users get 10% off their first purchase.

Try Firecrawl free
Your own AI agent, running 24/7 with QwikClaw logoYour own AI agent, running 24/7 with QwikClaw

QwikClaw sets up and runs an always-on OpenClaw agent for you. One click, no config files, no server setup.

Deploy now
One API to scrape, enrich, and extract the internet. logoOne API to scrape, enrich, and extract the internet.

Context.dev gives your agents a single API to scrape, enrich, and extract live web data — no proxies, no parsers, no maintenance.

Start building free
SetupClaw: done-for-you OpenClaw for founders & exec teams logoSetupClaw: done-for-you OpenClaw for founders & exec teams

White-glove OpenClaw for founders and exec teams (4–50+ employees): we install, harden, integrate your tools, and maintain it — secured from day one.

Get it set up for you
SEO data APIs for your agent, $1 free credit logoSEO data APIs for your agent, $1 free credit

DataForSEO gives your agent live access to SERP results, keyword data, backlinks, and on-page SEO data through one API. New accounts get a $1 credit, good for up to 20,000 keyword or backlink lookups.

Try DataForSEO free
Reach 47,000+ AI builders

A flat monthly placement in front of developers actively installing AI tools. No lock-in, cancel anytime.

Advertise here
Webhook Subscriptions logo

Webhook Subscriptions

NousResearch/hermes-agent

Summary

Webhook subscriptions: event-driven agent runs.

SKILL.md

Webhook Subscriptions

Create dynamic webhook subscriptions so external services (GitHub, GitLab, Stripe, CI/CD, IoT sensors, monitoring tools) can trigger Hermes agent runs by POSTing events to a URL.

Setup (Required First)

The webhook platform must be enabled before subscriptions can be created. Check with:

hermes webhook list

If it says "Webhook platform is not enabled", set it up:

Option 1: Setup wizard

hermes gateway setup

Follow the prompts to enable webhooks, set the port, and set a global HMAC secret.

Option 2: Manual config

Add to ~/.hermes/config.yaml:

platforms:
  webhook:
    enabled: true
    extra:
      host: "0.0.0.0"
      port: 8644
      secret: "generate-a-strong-secret-here"

Option 3: Environment variables

Add to ~/.hermes/.env:

WEBHOOK_ENABLED=true
WEBHOOK_PORT=8644
WEBHOOK_SECRET=generate-a-strong-secret-here

After configuration, start (or restart) the gateway:

hermes gateway run
# Or if using systemd:
systemctl --user restart hermes-gateway

Verify it's running:

curl http://localhost:8644/health

Commands

All management is via the hermes webhook CLI command:

Create a subscription

hermes webhook subscribe <name> \
  --prompt "Prompt template with {payload.fields}" \
  --events "event1,event2" \
  --description "What this does" \
  --skills "skill1,skill2" \
  --deliver telegram \
  --deliver-chat-id "12345" \
  --secret "optional-custom-secret"

Returns the webhook URL and HMAC secret. The user configures their service to POST to that URL.

List subscriptions

hermes webhook list

Remove a subscription

hermes webhook remove <name>

Test a subscription

hermes webhook test <name>
hermes webhook test <name> --payload '{"key": "value"}'

Prompt Templates

Prompts support {dot.notation} for accessing nested payload fields:

  • {issue.title} — GitHub issue title
  • {pull_request.user.login} — PR author
  • {data.object.amount} — Stripe payment amount
  • {sensor.temperature} — IoT sensor reading

If no prompt is specified, the full JSON payload is dumped into the agent prompt.

Common Patterns

GitHub: new issues

hermes webhook subscribe github-issues \
  --events "issues" \
  --prompt "New GitHub issue #{issue.number}: {issue.title}\n\nAction: {action}\nAuthor: {issue.user.login}\nBody:\n{issue.body}\n\nPlease triage this issue." \
  --deliver telegram \
  --deliver-chat-id "-100123456789"

Then in GitHub repo Settings → Webhooks → Add webhook:

  • Payload URL: the returned webhook_url
  • Content type: application/json
  • Secret: the returned secret
  • Events: "Issues"

GitHub: PR reviews

hermes webhook subscribe github-prs \
  --events "pull_request" \
  --prompt "PR #{pull_request.number} {action}: {pull_request.title}\nBy: {pull_request.user.login}\nBranch: {pull_request.head.ref}\n\n{pull_request.body}" \
  --skills "github-code-review" \
  --deliver github_comment

Stripe: payment events

hermes webhook subscribe stripe-payments \
  --events "payment_intent.succeeded,payment_intent.payment_failed" \
  --prompt "Payment {data.object.status}: {data.object.amount} cents from {data.object.receipt_email}" \
  --deliver telegram \
  --deliver-chat-id "-100123456789"

CI/CD: build notifications

hermes webhook subscribe ci-builds \
  --events "pipeline" \
  --prompt "Build {object_attributes.status} on {project.name} branch {object_attributes.ref}\nCommit: {commit.message}" \
  --deliver discord \
  --deliver-chat-id "1234567890"

Generic monitoring alert

hermes webhook subscribe alerts \
  --prompt "Alert: {alert.name}\nSeverity: {alert.severity}\nMessage: {alert.message}\n\nPlease investigate and suggest remediation." \
  --deliver origin

Direct delivery (no agent, zero LLM cost)

For use cases where you just want to push a notification through to a user's chat — no reasoning, no agent loop — add --deliver-only. The rendered --prompt template becomes the literal message body and is dispatched directly to the target adapter.

Use this for:

  • External service push notifications (Supabase/Firebase webhooks → Telegram)
  • Monitoring alerts that should forward verbatim
  • Inter-agent pings where one agent is telling another agent's user something
  • Any webhook where an LLM round trip would be wasted effort
hermes webhook subscribe antenna-matches \
  --deliver telegram \
  --deliver-chat-id "123456789" \
  --deliver-only \
  --prompt "🎉 New match: {match.user_name} matched with you!" \
  --description "Antenna match notifications"

The POST returns 200 OK on successful delivery, 502 on target failure — so upstream services can retry intelligently. HMAC auth, rate limits, and idempotency still apply.

Requires --deliver to be a real target (telegram, discord, slack, github_comment, etc.) — --deliver log is rejected because log-only direct delivery is pointless.

Security

  • Each subscription gets an auto-generated HMAC-SHA256 secret (or provide your own with --secret)
  • The webhook adapter validates signatures on every incoming POST
  • Static routes from config.yaml cannot be overwritten by dynamic subscriptions
  • Subscriptions persist to ~/.hermes/webhook_subscriptions.json

How It Works

  1. hermes webhook subscribe writes to ~/.hermes/webhook_subscriptions.json
  2. The webhook adapter hot-reloads this file on each incoming request (mtime-gated, negligible overhead)
  3. When a POST arrives matching a route, the adapter formats the prompt and triggers an agent run
  4. The agent's response is delivered to the configured target (Telegram, Discord, GitHub comment, etc.)

Troubleshooting

If webhooks aren't working:

  1. Is the gateway running? Check with systemctl --user status hermes-gateway or ps aux | grep gateway
  2. Is the webhook server listening? curl http://localhost:8644/health should return {"status": "ok"}
  3. Check gateway logs: grep webhook ~/.hermes/logs/gateway.log | tail -20
  4. Signature mismatch? Verify the secret in your service matches the one from hermes webhook list. GitHub sends X-Hub-Signature-256, GitLab sends X-Gitlab-Token.
  5. Firewall/NAT? The webhook URL must be reachable from the service. For local development, use a tunnel (ngrok, cloudflared).
  6. Wrong event type? Check --events filter matches what the service sends. Use hermes webhook test <name> to verify the route works.