Using Hookdeck with OpenClaw: Reliable Webhooks for Your AI Agent
OpenClaw's webhook system turns any HTTP-capable service into a trigger for your personal AI assistant. GitHub pushes a commit, Gmail receives an email, a Telegram bot fires a command - and OpenClaw wakes up, processes the event, and acts.
OpenClaw is evolving fast, and its webhook system is already impressively capable for a young project. That said, there are some rough edges that come with running webhooks through a single Node.js process. When it restarts - for a config change, an update, or an unexpected crash - inbound webhooks hit a closed port and vanish. There's no built-in queue, no retry layer, and no dashboard showing what arrived or what was lost.
This is where Hookdeck's Event Gateway can help. The Event Gateway sits between your webhook producers and OpenClaw, providing a secure tunnel (no port exposure), persistent URLs, automatic retries, deduplication, and full observability - without changing how OpenClaw itself works.
This tutorial walks through how to set up webhooks in OpenClaw, reliability problems you may run into, and how you can wire Hookdeck into an OpenClaw setup to fix them.
Understanding OpenClaw's two hook systems
OpenClaw has two distinct systems that share the "hooks" name, and it's easy to confuse them. OpenClaw's docs use Hooks for the internal system and Webhooks for the external one.
Webhooks in OpenClaw are endpoints that receive requests from external services (like GitHub, Gmail, Telegram, cron jobs, or any HTTP client) and are the focus of this tutorial.
Hooks (sometimes called "internal hooks" for clarity) are an event-driven plugin system that runs inside the gateway. They react to internal events such as /new, /reset, /stop, or lifecycle events.
The two systems can work together (a hook could fire in response to an event triggered by a webhook) but they serve fundamentally different purposes. In this tutorial, we're talking about the external Webhooks.
How OpenClaw webhooks work
Enabling webhooks
Webhooks are off by default. You enable them in ~/.openclaw/openclaw.json:
{
"hooks": {
"enabled": true,
"token": "your-secret-token",
"path": "/hooks"
}
}
hooks.tokenis required whenhooks.enabledistrue- every inbound request must present it.hooks.pathdefaults to/hooksand sets the URL prefix on your gateway (which runs on port18789by default).
Authentication
External services authenticate against your hook endpoint in one of three ways:
Authorization: Bearer <token>(recommended)x-openclaw-token: <token>?token=<token>(deprecated; logs a warning and will be removed in a future major release)
Use a dedicated token for hooks. Don't reuse your gateway auth token - if a webhook provider leaks it, you don't want that to also unlock your gateway.
Many webhook providers (GitHub, Twilio, Stripe) only let you configure a URL and don't support custom headers. With the deprecated query-parameter auth being removed, you can't easily register a URL with ?token=... and have OpenClaw accept it. The Event Gateway solves this: receive the webhook from the provider (verify the provider's signature at the source), then configure the connection's destination with Bearer authentication so the Event Gateway adds the Authorization: Bearer <token> header when forwarding to OpenClaw.
The three endpoint types
OpenClaw exposes three types of hook endpoints.
POST /hooks/wakeis the simplest. This is the endpoint for fire-and-forget triggers - a CI build failed, a form was submitted, a sensor reading crossed a threshold. It accepts a JSON body with atextfield (the event description your AI will process) and an optionalmodefield ("now"for immediate processing,"next-heartbeat"to batch it into the next cycle). It enqueues a system event for the main session and returns200.POST /hooks/agentruns an isolated agent turn with its own session key and returns202(async run started).POST /hooks/<name>(mapped hooks) resolves custom hook names viahooks.mappingsin your config. This is how you build integrations for services that don't match the wake/agent payload format. A mapping turns arbitrary payloads into wake or agent actions, with optional templates or code transforms.
Response codes
| Code | Meaning |
|---|---|
200 | /hooks/wake - event enqueued |
202 | /hooks/agent - async run started |
401 | Authentication failure |
400 | Invalid payload |
413 | Oversized payload |
Security recommendations
The official docs are clear on this: keep hook endpoints behind loopback, a tailnet, or a trusted reverse proxy. Hook payloads are treated as untrusted and wrapped with safety boundaries by default. The allowUnsafeExternalContent: true flag disables this safety wrapper for a specific mapping, but should only be used for trusted internal sources.
The Event Gateway can act as that trusted reverse proxy: it verifies webhook signatures at the edge, then forwards authenticated requests to OpenClaw. For services that can't customize HTTP headers at all (some IoT devices, legacy systems), the Event Gateway receives the original webhook and forwards it to OpenClaw with proper authentication.
Setting up the Event Gateway with OpenClaw
Now for the fun part - let's wire this up. The whole process takes about five minutes.
Step 1: Install the Hookdeck CLI
The Hookdeck CLI creates a tunnel from the Event Gateway to your OpenClaw instance. Unlike exposing a port, it makes an outbound WebSocket connection from your machine to the Event Gateway, so you don't need to expose any ports or map your OpenClaw instance to a public endpoint. Whether you're running OpenClaw locally, on a home server, or in the cloud, the CLI lets third-party services send webhooks to the Event Gateway while your instance stays unreachable from the internet.
macOS:
brew install hookdeck/hookdeck/hookdeck
Linux:
# Download the latest release
curl -sL https://github.com/hookdeck/hookdeck-cli/releases/latest/download/hookdeck_linux_amd64.tar.gz | tar xz
sudo mv hookdeck /usr/local/bin/
Windows (Scoop):
scoop bucket add hookdeck https://github.com/hookdeck/scoop-hookdeck-cli.git
scoop install hookdeck
Docker:
docker pull hookdeck/hookdeck-cli
Step 2: Authenticate
hookdeck login
Follow the browser prompt to create an account or sign in. You can skip this and a temporary guest account will be created - webhooks still work, but you won't see events in the main dashboard. It's worth logging in so your event history sticks around between sessions and you can replay things later.
For production, headless, or CI/CD environments where no browser flow is possible, use hookdeck ci --api-key $HOOKDECK_API_KEY instead. Get the API key from your project settings in the Hookdeck dashboard. See the CLI documentation for details.
Step 3: Create connections
Create the connections first using the CLI, so you can then run a single listen command. OpenClaw's gateway runs on port 18789 by default:
# Create connection for wake hooks
hookdeck connection upsert openclaw-hooks \
--source-name openclaw-hooks --source-type WEBHOOK \
--destination-type CLI --destination-name cli-openclaw \
--destination-path /hooks/wake \
--destination-auth-method bearer --destination-bearer-token "$OPENCLAW_HOOK_TOKEN"
# Create connection for agent hooks (if you use /hooks/agent)
hookdeck connection upsert openclaw-agent \
--source-name openclaw-agent --source-type WEBHOOK \
--destination-type CLI --destination-name cli-openclaw \
--destination-path /hooks/agent \
--destination-auth-method bearer --destination-bearer-token "$OPENCLAW_HOOK_TOKEN"
# Create connection for mapped hooks (e.g. Gmail preset)
hookdeck connection upsert openclaw-gmail \
--source-name openclaw-gmail --source-type WEBHOOK \
--destination-type CLI --destination-name cli-openclaw \
--destination-path /hooks/gmail \
--destination-auth-method bearer --destination-bearer-token "$OPENCLAW_HOOK_TOKEN"
Add source verification (signature verification) so the Event Gateway only accepts events from the expected provider. For GitHub, for example, you'd use --source-type GITHUB with the webhook secret. For other providers, see the verification guide. Without verification, anyone who discovers your Source URL could send events to OpenClaw.
Each connection uses a different --destination-path so events route to the correct OpenClaw endpoint. Alternatively, configure the path in the Hookdeck dashboard.
Step 4: Start listening
With connections created, run a single listen command for all sources:
hookdeck listen 18789 openclaw-hooks,openclaw-agent,openclaw-gmail
This establishes one session forwarding events from all three sources to your OpenClaw instance. Each source has its own persistent Event URL, and each connection routes to its configured path.
Example terminal output:
Listening on 3 sources • 3 connections
openclaw-hooks
│ Requests to → https://hkdk.events/src_xxx1
└─ Forwards to → http://localhost:18789/hooks/wake (cli-openclaw)
openclaw-agent
│ Requests to → https://hkdk.events/src_xxx2
└─ Forwards to → http://localhost:18789/hooks/agent (cli-openclaw)
openclaw-gmail
│ Requests to → https://hkdk.events/src_xxx3
└─ Forwards to → http://localhost:18789/hooks/gmail (cli-openclaw)
You can use the interactive CLI controls to inspect webhooks in real time: press d to view full request/response details, up/down arrows to navigate between events, and o to open an event in the dashboard.
If you only need wake hooks, create and listen to that one source:
hookdeck listen 18789 openclaw-hooks --path /hooks/wake
Step 5: Register the Event Gateway URL with your providers
Replace your OpenClaw gateway URL with the Event Gateway URL (the URL of the Source used in your connections) everywhere you've configured webhooks.
GitHub (repository Settings > Webhooks):
- Payload URL:
https://hkdk.events/src_abc123xyz - Content type:
application/json - Secret: configure in the Event Gateway for HMAC signature verification
- Payload URL:
Gmail: OpenClaw has a Gmail preset (
hooks.presets: ["gmail"]) that uses Gmail Pub/Sub push subscriptions. Runopenclaw webhooks gmail setupto configure it, then point the Pub/Sub push subscription at the Event Gateway URL.Telegram Bot API: Using Telegram in webhook mode through the Event Gateway is actually more reliable than the default polling mode, since you avoid
getUpdatestimeout issues:
curl "https://api.telegram.org/bot<BOT_TOKEN>/setWebhook?url=https://hkdk.events/src_abc123xyz"
That's it! Your webhooks are now flowing through the Event Gateway, giving you a persistent URL, automatic retries, deduplication, and a dashboard to see what's happening.
Common Hookdeck CLI commands
| Command | Purpose |
|---|---|
hookdeck login | Authenticate with your Hookdeck account |
hookdeck connection upsert openclaw-hooks ... | Create/update connections (see Step 3) |
hookdeck listen 18789 openclaw-hooks,openclaw-agent,openclaw-gmail | Forward events from all sources to OpenClaw |
hookdeck listen 18789 openclaw-hooks --path /hooks/wake | Simple: forward wake events only |
hookdeck ci --api-key $KEY | Authenticate in CI/CD environments |
hookdeck listen 18789 source --path /path --insecure | Allow self-signed HTTPS certs (local dev only) |
OpenClaw webhook limitations and growing pains
If you're already encountering an issue with webhooks in OpenClaw, below covers common problems and how the Event Gateway can help solve them.
Missed webhooks during restarts
The Problem: When OpenClaw's gateway restarts - whether from a config change, an update, or an unexpected crash - the webhook endpoint goes down with it. Any webhooks that arrive during that window get a connection error and are silently lost. This is the most common pain point in the community. Users report dropped voice notes, Telegram bots that stop responding after migrations, and cronjobs that hang with gateway timeout errors.
Why It Happens: OpenClaw's gateway is a single Node.js process that handles everything in-memory. There's no persistent queue sitting in front of it, so when the process stops, the port closes and there's nowhere for incoming requests to go. A message queue that survives restarts has been suggested by the community but isn't yet part of the architecture.
Workarounds:
- Minimise restarts by batching config changes rather than applying them one at a time
- Use a process manager (like
pm2orsystemd) with automatic restart to shrink the downtime window - If you're on a VPS, consider running behind a reverse proxy that can return a 503 (which some providers will retry) instead of a connection refused
How the Event Gateway Helps: The Event Gateway sits in front of your gateway and accepts webhooks on its behalf. Every event is persisted to durable storage before the Event Gateway returns 200 OK to the provider. If OpenClaw is mid-restart, the events just queue up. When the gateway comes back, the Event Gateway delivers them automatically - or you can replay them manually from the dashboard. You can restart as often as you like without losing a single event.
- Automatic retries handle the common case: if the gateway is briefly unavailable (restarting, crashed, slow to respond), the Event Gateway retries with configurable backoff - up to 50 attempts by default. Retries kick in on timeouts (60-second window), network errors, or non-2xx status codes.
- Manual replay is there for bigger problems. From the dashboard, filter for events that failed during a specific time window, inspect their payloads, and replay them individually or in bulk. Really handy after a long outage - instead of having to send the webhook again, you can just replay it.
Gateway crashes and instability
The Problem: The gateway can crash unexpectedly. Each crash leaves the webhook endpoint unreachable until the process restarts. If you're mid-conversation, responses just stop with no explanation.
Why It Happens: As a Node.js application making lots of outbound API calls (to LLM providers, messaging platforms, external services), unexpected errors can bring down the process. OpenClaw is evolving fast, and the project is actively improving error handling, but with the pace of development, new edge cases keep surfacing.
Workarounds:
- Use
pm2orsystemdwith auto-restart to get the gateway back up quickly - Monitor with
openclaw status --deepand set up health check alerts - Keep an eye on the OpenClaw releases page - crash fixes land frequently
How the Event Gateway Helps: The Event Gateway automatically retries failed deliveries with configurable backoff - up to 50 attempts by default. If the gateway crashes and comes back 30 seconds later, the Event Gateway simply re-delivers the events that failed. Events that can't be delivered after all retries surface as Issues in the dashboard (similar to a dead-letter queue), so you can inspect and replay them once things stabilise.
Channel-specific connection drops
The Problem: Some messaging channels have their own reliability quirks. Telegram's polling mechanism can exit on getUpdates timeouts without reconnecting. Discord's bot occasionally stops receiving MESSAGE_CREATE events entirely, and responses that take longer than two minutes to process sometimes never arrive.
Why It Happens: Each messaging platform has its own connection model - long polling, WebSockets, HTTP callbacks - and each has different failure modes. OpenClaw integrates with 12+ platforms, and keeping all those connections healthy simultaneously is genuinely hard. The community is actively reporting and fixing these issues.
Workarounds:
- For Telegram, a common approach is a watchdog script that checks channel status every couple of minutes and triggers a gateway restart if Telegram goes down
- For Discord, make sure you have the right intents enabled (
GuildMessages,MessageContent) - Use
openclaw status --deepto regularly check channel health
How the Event Gateway Helps: For platforms that support webhook delivery (like Telegram's webhook mode instead of polling), routing through the Event Gateway avoids the connection-drop problem entirely. Instead of OpenClaw polling Telegram, Telegram pushes to the Event Gateway's always-available URL, and the Event Gateway forwards to your gateway. No polling timeouts, no dropped connections.
No built-in deduplication for webhooks
The Problem: When a webhook provider retries a delivery (because it didn't get a response fast enough, or got a temporary error), OpenClaw processes the event again. There's no general-purpose mechanism to detect and skip duplicates. Your AI might summarise the same email twice, review the same PR twice, or send duplicate Telegram messages.
Why It Happens: OpenClaw does implement deduplication for Telegram specifically (createTelegramUpdateDedupe), but there's no equivalent layer for generic webhook events. Building deduplication requires tracking event IDs or content hashes with a time window, which adds infrastructure complexity that isn't part of the current in-memory model.
Workarounds:
- Use
sessionKeyon the/hooks/agentendpoint to group related events - this gives your AI context to recognise it's already handled something - Design your prompts defensively so that processing the same event twice doesn't cause harmful side effects
- Some providers include unique event IDs in their payloads - you can check these in your hook mappings
How the Event Gateway Helps: The Event Gateway's deduplication rules filter out duplicate events before they reach OpenClaw. You can match on the full payload, specific headers (like GitHub's X-GitHub-Delivery), or a composite key built from multiple fields. The time window is configurable from 1 second to 1 hour.
Content-based deduplication
The simplest approach: drop events with identical payloads within a time window. Great for retry storms where the same event shows up five times in a row:
{
"type": "deduplicate",
"window": 60000
}
Any event with the same body arriving within 60 seconds is ignored. The time window is configurable between 1 second and 1 hour.
Header-based deduplication
Use a provider's unique event ID to detect duplicates, even if the payload changes slightly between retries. For example:
{
"type": "deduplicate",
"window": 300000,
"include_fields": ["headers.x-github-delivery"]
}
Since GitHub sends a unique X-GitHub-Delivery header with each event, we're using it to check if the same ID arrives twice within five minutes. If so, the duplicate is dropped.
Composite-key deduplication
For services that don't provide unique IDs, build a key from multiple fields:
{
"type": "deduplicate",
"window": 600000,
"include_fields": [
"body.repository.full_name",
"body.action",
"body.pull_request.number"
]
}
This ensures that the same action on the same PR in the same repo is only processed once within ten minutes.
Limited webhook visibility
The Problem: There's no dashboard showing which webhooks arrived, which were processed successfully, which failed, and which were lost during downtime. When something goes wrong, you're piecing things together from openclaw logs, provider delivery dashboards (if they exist), and timestamps.
Why It Happens: OpenClaw's built-in observability tools - openclaw logs, openclaw status --deep, and the command-logger internal hook - are designed for general gateway health, not specifically for webhook traffic. The project's focus has understandably been on the AI agent capabilities and messaging integrations rather than webhook infrastructure tooling.
Workarounds:
- Enable the
command-loggerinternal hook to write an audit trail to~/.openclaw/logs/commands.log - Use
openclaw status --deepto probe channel health - Check your webhook providers' delivery logs for failed attempts
How the Event Gateway Helps: The Event Gateway provides a full dashboard that logs every request, event, and delivery attempt with searchable filters for source, status code, date range, and payload content. You can see exactly what came in, what was delivered, and what failed - plus set up Issue Triggers and notifications to catch problems before your users do.
The dashboard
Every request, event, and delivery attempt is logged and searchable. You can filter by source, status code, date range, or even dig into specific payload fields. Click into any event to see the full request headers, body, and your gateway's response. If you notice a pattern - say, a spike in 4xx errors every time you update your OpenClaw config - you'll spot it here. The dashboard URL is printed when you runhookdeck listen. You can also pressoon any event in the interactive CLI to jump straight to it in the dashboard.Issues and notifications
The Event Gateway automatically creates Issues when it spots recurring problems - your gateway returning 5xx errors, a spike in failed deliveries, that kind of thing. Failed events stay right there in the same system with full context, and you can inspect and retry them individually or in bulk. You can set up Issue Triggers and notifications so you hear about problems before your users do.
Single shared webhook token
The Problem: All webhook integrations share one global hooks.token. Services like GitHub and Notion can sign their payloads with HMAC signatures, but OpenClaw doesn't verify these provider-specific signatures - it only checks its own bearer token. There's no way to rotate credentials per integration, and revoking a compromised token means updating every provider at once.
Why It Happens: The current auth model is straightforward by design - a single shared secret keeps configuration simple. Provider-specific signature verification would require per-source configuration and knowledge of each provider's signing scheme, which adds complexity.
Workarounds:
- Keep your hook endpoint behind a loopback address, tailnet, or trusted reverse proxy so the token is a second layer rather than the only layer
- Use long, random tokens and rotate them periodically
- For services that can't customise headers at all, use an intermediary (like Event Gateway, Zapier or Make) to add the auth header
How the Event Gateway Helps: The Event Gateway supports per-source signature verification out of the box. You can validate GitHub's HMAC-SHA256 signature on one Source, Notion's signing secret on another, and Calendly's HMAC on a third - all independently. The Event Gateway verifies the webhook actually came from the claimed provider, then forwards it to OpenClaw with Bearer authentication (configure the destination with your hook token). This gives you proper defence in depth without needing to modify OpenClaw's auth model.
Resources
OpenClaw Documentation
Hookdeck Documentation
- Hookdeck Basics - core concepts
- The Hookdeck CLI - installation and usage
- Receive and Process Webhooks - architecture guide
- Deduplication Guide - strategies and configuration
- Issues & Notifications - monitoring and alerting