OpenClaw

View as Markdown

Dial integrates with OpenClaw in two parts:

  1. Driving Dial so the agent can send texts, place calls, and manage numbers. Pick one of two ways below — the CLI skill or Dial’s native MCP server.
  2. Inbound event handling so Dial events (inbound SMS, completed calls) reach OpenClaw without the agent having to poll.

Install

There are two ways to give an OpenClaw agent the ability to drive Dial. Both do the same outbound job — let the agent send SMS, place calls, and manage numbers — so pick one:

  • CLI skill — drops a skill into OpenClaw’s config that teaches the agent to shell out to the dial CLI.
  • MCP server — registers Dial’s MCP server so the agent calls Dial’s tools directly, no CLI shell-out.

First, get the dial CLI on your PATH:

$curl -fsSL https://getdial.ai/install | bash

Then drop the OpenClaw-specific Dial skill into your config:

$dial onboard --code <code> --agent openclaw

onboard finishes verification first, then copies the Dial skill into OpenClaw’s config directory. The agent loads it on demand and can drive the CLI — see the CLI reference for the full surface.

To rerun the copy later (for example, after a CLI upgrade), run dial onboard --agent openclaw again — the verification step is a no-op once you’re onboarded, and the skill file is overwritten in place.

Option 2 — MCP server

Register Dial as an MCP server and OpenClaw exposes its tools to your agents natively. Use the local (stdio) form — npx -y @getdial/cli mcp, which reuses the saved CLI key — or the remote form at https://getdial.ai/mcp (OAuth in the browser). See the MCP page for the full tool list and the remote OAuth flow.

Add it with the openclaw mcp add command, or declare it directly in the config:

$openclaw mcp add dial \
> --command npx \
> --arg -y \
> --arg @getdial/cli \
> --arg mcp

Changes to mcp.* hot-apply, so the agent picks up the new server without a Gateway restart. For OAuth on the remote form, run openclaw mcp login dial to complete the browser flow on first use. See OpenClaw’s MCP reference for the full command and config surface.

Inbound event handling

You have two ways to route Dial events into OpenClaw. Both rely on Dial’s listen daemon — install it first:

$dial listen install

The daemon owns the fan-out queue. See Listen service.

Reference reading on the OpenClaw side:

  • OpenClaw — Webhooks — the HTTP endpoints, auth, and hooks.mappings.
  • OpenClaw — Hooks — internal lifecycle hooks (TypeScript handlers that fire inside the Gateway on events like command:new).

Option 1 — Webhook

Use OpenClaw’s Gateway hooks block. The daemon POSTs each Dial event to a Gateway endpoint authenticated with a bearer token; a hooks.mappings entry translates the Dial event shape into a Gateway wake or agent action.

1. Enable hooks on the OpenClaw Gateway

Turn on the hooks block in the Gateway config (JSON5):

1{
2 hooks: {
3 enabled: true,
4 token: "generate-a-strong-token-here",
5 path: "/hooks",
6 },
7}
KeyDescription
hooks.enabledToggles webhook acceptance on the Gateway.
hooks.tokenShared bearer token. Every incoming POST must carry Authorization: Bearer <token> (or x-openclaw-token; bearer is recommended).
hooks.pathEndpoint base path the Gateway listens on (defaults to /hooks).

Keep the Gateway bound to loopback (127.0.0.1) or a trusted reverse proxy — Dial fans out only to local loopback hosts, and exposing the hooks endpoint on a public interface would leak it. The OpenClaw docs also recommend setting hooks.allowedAgentIds to restrict which agents a hook can trigger.

Restart the Gateway so the new config takes effect.

2. Map an incoming Dial event onto a Gateway action

Dial’s listen daemon posts the raw event JSON as-is — it doesn’t shape the body. The Gateway’s built-in /hooks/wake and /hooks/agent endpoints expect their own field names (text, message), so a Dial event won’t fit them directly. Use a custom mapping under hooks.mappings to translate Dial’s event shape into one of the built-in actions:

1{
2 hooks: {
3 enabled: true,
4 token: "generate-a-strong-token-here",
5 path: "/hooks",
6 mappings: {
7 // Dial fans out to /hooks/dial; the mapping turns the event into a wake.
8 dial: {
9 action: "wake",
10 // Templates can reference fields on the incoming Dial event JSON.
11 text: "Dial event {{type}} on {{to}}",
12 mode: "now",
13 },
14 },
15 },
16}

See the OpenClaw Webhooks reference for the full mapping syntax (template strings vs code transforms, agent actions, agent selection).

3. Register the Gateway URL as a Dial local target

Read the token out of the Gateway config and hand it to dial local-target add url:

$CONFIG=~/.openclaw/gateway/config.json5
$TOKEN=$(jq -r '.hooks.token' "$CONFIG")
$HOOK_PATH=$(jq -r '.hooks.path' "$CONFIG")
$
$# Default Gateway port is 18789 — set --port in the Gateway config to override.
$dial local-target add url "http://127.0.0.1:18789${HOOK_PATH}/dial" --bearer "$TOKEN"

--bearer sends Authorization: Bearer <token> on every fan-out POST, which is the form the Gateway expects.

No daemon restart is required — the fan-out registry updates on the fly.

4. Verify

$# Send yourself an SMS to one of your Dial numbers, then check:
$dial listen status # confirm the fan-out POST went out

Check the Gateway logs for an accepted POST on <hooks.path>/dial. To remove the wiring later, run dial local-target remove <url>.

Option 2 — CLI command target

Skip the Gateway hooks entirely and spawn a fresh OpenClaw agent session per Dial event using a CLI command target. The daemon runs your handler with the event JSON as the final positional argument; the handler builds a prompt and launches OpenClaw detached. Useful when:

  • You don’t want to enable the Gateway hooks block at all.
  • You’d rather not maintain hooks.mappings to reshape Dial’s payload.
  • A one-shot agent run per event is enough — no need for the Gateway’s wake/agent action plumbing.

1. Write a handler

$#!/usr/bin/env bash
$# /usr/local/bin/handle-dial-event-openclaw
$event="$1"
$
$type=$(jq -r '.type' <<<"$event")
$from=$(jq -r '.from // ""' <<<"$event")
$body=$(jq -r '.body // ""' <<<"$event")
$
$prompt=$(cat <<EOF
>A Dial event just arrived. Decide what to do and act on it.
>
> type: $type
> from: $from
> body: $body
>
>raw event JSON:
>$event
>EOF
>)
$
$# Detach a fresh OpenClaw session and return right away.
$nohup openclaw agent --message "$prompt" </dev/null >>~/.dial/openclaw.log 2>&1 &
$disown
$exit 0

openclaw agent runs a single turn from the command line — no inbound chat message needed. Add --agent <id> to target a specific configured agent, or --local to run embedded instead of going through the Gateway.

2. Register

$chmod +x /usr/local/bin/handle-dial-event-openclaw
$dial local-target add cmd /usr/local/bin/handle-dial-event-openclaw

The nohup … & disown pattern keeps OpenClaw running after the handler exits, so a multi-minute agent run never collides with the daemon’s per-attempt --timeout. See CLI command target for the full reference, delivery semantics, and the once-retry behavior.

Use it

Either install path works the same in use — just ask your OpenClaw agent in plain language:

Send an SMS to +14155550123 with the body “running late, ETA 10 min”.

The agent picks the right action and runs it. With the MCP server it calls Dial’s tools directly; with the CLI skill it picks the right dial command and shells out. See Using Dial from an agent for more examples.