> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.getdial.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getdial.ai/_mcp/server.

# OpenClaw

> Use Dial from an OpenClaw agent — install the Dial skill and route inbound events into OpenClaw.

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](/integrations/tools/mcp) so the agent calls Dial's tools directly, no CLI shell-out.

### Option 1 — CLI skill (Recommended)

First, get the `dial` CLI on your PATH:

```bash title="Shell install"
curl -fsSL https://getdial.ai/install | bash
```

```text title="Agent prompt"
Follow https://getdial.ai/skills.md to install and onboard the dial CLI.
```

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

```bash
dial auth verify-otp --code <code> --agent openclaw
```

`auth verify-otp` verifies your code 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](/documentation/cli/commands) for the full surface.

To rerun the copy later (for example, after a CLI upgrade), run `dial auth verify-otp --agent openclaw` again — the verification step is a no-op once you're signed in, 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](/integrations/tools/mcp) 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:

```bash title="openclaw mcp add (local stdio)"
openclaw mcp add dial \
  --command npx \
  --arg -y \
  --arg @getdial/cli \
  --arg mcp
```

```bash title="openclaw mcp add (remote)"
openclaw mcp add dial \
  --url https://getdial.ai/mcp \
  --transport streamable-http \
  --auth oauth
```

```json5 title="~/.openclaw/openclaw.json — local stdio"
{
  mcp: {
    servers: {
      dial: {
        command: "npx",
        args: ["-y", "@getdial/cli", "mcp"],
      },
    },
  },
}
```

```json5 title="~/.openclaw/openclaw.json — remote"
{
  mcp: {
    servers: {
      dial: {
        url: "https://getdial.ai/mcp",
        transport: "streamable-http",
        auth: "oauth",
      },
    },
  },
}
```

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](https://docs.openclaw.ai/cli/mcp) 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:

```bash
dial listen install
```

The daemon owns the fan-out queue. See [Listen service](/documentation/cli/listen-service).

Reference reading on the OpenClaw side:

* [OpenClaw — Webhooks](https://docs.openclaw.ai/automation/cron-jobs#webhooks) — the HTTP endpoints, auth, and `hooks.mappings`.
* [OpenClaw — Hooks](https://docs.openclaw.ai/automation/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):

```json5
{
  hooks: {
    enabled: true,
    token: "generate-a-strong-token-here",
    path: "/hooks",
  },
}
```

| Key             | Description                                                                                                                         |
| --------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `hooks.enabled` | Toggles webhook acceptance on the Gateway.                                                                                          |
| `hooks.token`   | Shared bearer token. Every incoming POST must carry `Authorization: Bearer <token>` (or `x-openclaw-token`; bearer is recommended). |
| `hooks.path`    | Endpoint 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:

```json5
{
  hooks: {
    enabled: true,
    token: "generate-a-strong-token-here",
    path: "/hooks",
    mappings: {
      // Dial fans out to /hooks/dial; the mapping turns the event into a wake.
      dial: {
        action: "wake",
        // Templates can reference fields on the incoming Dial event JSON.
        text: "Dial event {{type}} on {{to}}",
        mode: "now",
      },
    },
  },
}
```

See the OpenClaw [Webhooks reference](https://docs.openclaw.ai/automation/cron-jobs#webhooks) 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`:

```bash title="jq"
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"
```

```bash title="One-liner"
dial local-target add url \
  "http://127.0.0.1:18789$(jq -r '.hooks.path' ~/.openclaw/gateway/config.json5)/dial" \
  --bearer "$(jq -r '.hooks.token' ~/.openclaw/gateway/config.json5)"
```

`--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

```bash
# 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](/integrations/methods/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

```bash
#!/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

```bash
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](/integrations/methods/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](/documentation/get-started/using-dial-from-an-agent) for more examples.