Hermes Agent

Integration

Hermes Agent Webhooks: Setup and Delivery Troubleshooting

Set up signed Hermes Agent webhooks, choose agent or direct delivery, interpret 200/202/502 responses, and prevent unsafe retries and duplicate actions.

Quick answer

Hermes receives signed HTTP POST events at /webhooks/<route-name>. Choose an agent run for investigation, deliver_only: true for a literal notification without an LLM call, or cron_job to trigger an existing job. Read the response body as well as the status: HTTP 200 can mean delivered, ignored, or duplicate; HTTP 202 is not proof the work finished. Start with the route and destination, then use the monitoring checklist to verify the outcome.

Get FlyHermes Pro →

$49/mo or $39/mo billed yearly · AI included · 14‑day guarantee

Best for

Developers connecting a trusted service event to a bounded agent investigation.

Operators who need notification delivery without paying for a model turn.

Teams that can own ingress, credentials, retry policy, and destination verification.

Not a transaction queue or an exactly-once guarantee for purchases, payments, or other consequential actions.

Features

  • ✓Named incoming routes with event and payload filters
  • ✓Route secrets and provider-specific authentication; GitLab uses a token match rather than HMAC
  • ✓Agent runs, direct notifications, or existing-job triggers with distinct completion semantics
  • ✓Delivery-ID deduplication with a documented one-hour cache window
  • ✓Optional coalescing of distinct events for the same entity in agent mode
  • ✓Explicit chat/topic delivery and optional best-effort session mirroring

Setup path

  1. 1Choose the active Hermes profile and enable the webhook adapter with hermes gateway setup. The gateway runbook separates adapter health from model and channel health.
  2. 2Create a route in platforms.webhook.extra.routes or with hermes webhook subscribe <name>. Use a strong per-route secret and keep real values out of source control.
  3. 3Select one execution mode. Use deliver_only: true only with a real delivery target, not log; do not combine it with cron_job or coalesce.
  4. 4Set accepted events, narrow payload filters, and a prompt using only required fields. Configure deliver_extra.chat_id and, for a Telegram forum topic, deliver_extra.message_thread_id.
  5. 5Run the gateway and check curl http://localhost:8644/health. Then expose the route through your protected HTTPS ingress; a local health response does not prove external reachability.
  6. 6Send a harmless signed test from the provider with a stable delivery ID. Save the status and JSON response, then verify exactly one result in the intended destination. Test a filtered event and a same-ID retry separately before enabling consequential work.

Choose the mode before choosing the retry policy

Use the official route properties to choose who executes the work and who owns delivery. A webhook is not necessarily a fresh model conversation.

  • •Agent mode: investigate or summarize the event with a narrow tool scope; verify the eventual artifact and delivery separately.
  • •Direct delivery: the rendered prompt is the message. No agent runs, and the skills field is ignored. This avoids LLM tokens, not hosting or channel costs.
  • •Existing job: cron_job references an existing job by name or ID. Its prompt, skills, model, and delivery settings apply; route-level delivery and skills do not. Paused or disabled jobs are not fired. See cron diagnostics.

Read the response body before retrying

The official response-code guide distinguishes transport success from actual work. Preserve route, delivery ID, response status, timestamp, and destination evidence without logging secrets.

  • •HTTP 200 with status=delivered: direct delivery succeeded at the target-adapter boundary. Confirm the exact chat or topic during acceptance testing.
  • •HTTP 200 with status=ignored: inspect the reason. Filters may deliberately exclude an event; a script timeout, missing script, or nonzero exit can also return an ignored result. Do not count every 200 as a notification.
  • •HTTP 200 with status=duplicate: the delivery ID was seen within the cache window; no new delivery is expected.
  • •HTTP 202: an existing-job request is accepted for background work, or status=coalesced means the event is buffered. Track the eventual run rather than declaring completion.
  • •HTTP 502 in direct delivery: the target adapter rejected the message or raised. Check logs and the destination before a bounded retry; an uncertain external side effect must be reconciled, not assumed absent.
  • •HTTP 401 points to authentication; 404 to the route; 413 to body size; 429 to rate limiting. A disabled dynamic subscription returns 403. Do not retry an intentional disable as an availability failure.

Deduplication is not durable exactly-once execution

The documented idempotency cache uses delivery IDs such as X-GitHub-Delivery, svix-id, webhook-id, or X-Request-ID, with a one-hour window. That is a retry defense, not proof that an external write can never happen twice.

  • •Keep the same ID when retrying the same event. A fresh ID represents a different event to the receiver.
  • •For payments, tickets, or other consequential writes, persist an application-level idempotency key and read back the target before retrying an uncertain result.
  • •Use coalesce for distinct rapid updates to one entity, not as a replacement for delivery-ID deduplication. The latest payload replaces earlier buffered payloads.
  • •A missing coalescing key dispatches immediately. Pending groups flush on normal adapter disconnect; a hard process kill can lose the buffered window. Do not use this as the only record of business-critical events.

Keep delivery destination and conversation memory separate

For Telegram delivery, set the exact chat and forum topic. Without deliver_extra.chat_id, delivery falls back to the platform home channel. The target adapter must already be enabled and connected.

  • •By default each webhook event has its own session; replying in the destination chat does not automatically give that chat the webhook context.
  • •mirror_to_session: true appends successfully delivered text to the target chat transcript on a best-effort basis. It is skipped if no chat session exists and does not turn delivery into a guaranteed conversation handoff.
  • •Direct-delivery payload text enters history as a labelled user turn when mirrored. Enable this only for content you trust to enter that conversation, not arbitrary public issue text.

Authentication does not authorize every tool action

A valid signature identifies the sender, not the safety of every payload field. Use narrow templates and an explicit route toolset where needed; follow the MCP safety guide when a triggered agent can bridge private data into external writes.

  • •GitHub-style HMAC and GitLab token validation are different mechanisms. Match the source provider instead of treating every webhook signature the same.
  • •Keep INSECURE_NO_AUTH confined to temporary local tests. Do not remove authentication to make an internet-facing smoke test pass.
  • •Manual route toolsets replace the platform webhook toolset for that route; dynamic subscriptions cannot self-grant this setting through the subscribe command.
  • •Redact secrets and sensitive payload values from logs. An untrusted event should not choose a privileged recipient, workspace, or unrestricted command.

Acceptance checks before production traffic

This is a proposed operator test, not a benchmark or a claim that we sent test notifications. Run it in your own non-production destination with harmless payloads. The dashboard helps inspect state, but destination evidence is the completion check.

  • •Valid event: record one delivery ID and verify one message in the exact destination.
  • •Wrong event or unmatched filter: expect an ignored body and no agent work or message.
  • •Same-ID retry: expect duplicate handling within the documented window; verify no second message.
  • •Wrong signature: expect authentication rejection and no work.
  • •Unavailable target: capture the direct-delivery failure, restore the target, reconcile its state, then retry safely.
  • •Agent or job mode: verify the final artifact and delivery after acceptance. Do not equate HTTP 202 with task completion.

Self-hosted ingress or managed operations?

Self-hosted Hermes gives you control of routes, secrets, networking, logs, and recovery. It also leaves you responsible for TLS, gateway availability, channel permissions, retry safety, and provider usage. Compare self-hosting responsibilities and managed pricing if maintaining that chain is not your goal.

  • •Self-host when custom ingress and infrastructure control are requirements, not accidental chores.
  • •Evaluate FlyHermes as a managed operational option, not as proof that an arbitrary webhook route, ingress policy, or SLA is included. Confirm the exact workflow with the provider before moving production traffic.
  • •This site promotes FlyHermes. The boundary is operational ownership; self-hosted Hermes also has browser Chat through its dashboard.

Sources and scope

Checked October 18, 2026 against the official webhook documentation and dashboard subscription controls. These are documentation-backed instructions, not measured delivery latency or uptime.

  • •Installed versions can differ from current online docs. Check supported configuration before rollout.
  • •Incoming event routes and response delivery are the scope here; outbound lifecycle subscriptions are a separate mechanism.

Common setup issues

  • Health is green but no message arrives: read the POST response body, inspect filters or script outcomes, and verify the target adapter and exact chat/topic.
  • Repeated 403 after disabling a dynamic route: this is expected policy enforcement; the dashboard hot-reloads that subscription state on the next event.
  • Agent is not aware of the delivered alert: check session mirroring, whether a target chat session already exists, and the trust boundary before enabling mirroring.
  • Bursts still start multiple runs: distinguish same-ID retries from distinct events, and check that the coalescing key exists in every accepted payload.

Keep building the workflow

FAQ

Does HTTP 200 prove Hermes completed the webhook task?

No. Inspect the JSON body. A direct-delivery result can be delivered, ignored, or duplicate. Agent and existing-job completion require checking the resulting work separately.

Can I send a notification without an LLM call?

Yes. Set deliver_only to true with a real delivery target. The rendered prompt is delivered literally; no agent runs. Hosting and channel costs remain separate.

Does deduplication guarantee exactly-once side effects?

No. The documented delivery-ID cache has a one-hour window. Use durable application-level idempotency and reconcile the destination before retrying an uncertain consequential action.

Why does a reply not remember the webhook alert?

Webhook events have separate sessions by default. Optional mirror_to_session copies delivered text into an existing target chat session on a best-effort basis; only enable it for trusted content.

Related setup guides

Other Integrations