OpenClaw OP SMS Channel Plugin
Give your OpenClaw agent a real phone number.
This plugin connects OP phone numbers to OpenClaw as an SMS channel, so you can text your agent from any phone and let OpenClaw reply over SMS.
OP is built to be a simple path for agents to send and receive real texts. With this plugin, the intended setup flow is the same shape as the Hermes OP plugin: install the plugin, run one setup command, enter the OTP OP texts you, and let the plugin configure API keys, webhooks, and OpenClaw channel config.
Quickstart
openclaw plugins install JoshMayerr/openclaw-op-plugin --enable
cloudflared tunnel --url http://localhost:<openclaw-port>
openclaw plugin setup op \
--phone +14155551234 \
--webhook-url https://your-tunnel.trycloudflare.com/webhooks/op
openclaw restart
Then text your OP number. OpenClaw should receive the SMS through OP and reply from the same number.
The exact OpenClaw CLI command names may differ by host version. This repo exposes the plugin manifest, runtime entry, and setup entry that OpenClaw needs; host-level validation still needs to be run in an OpenClaw installation.
What this unlocks
- Text OpenClaw from any phone
- Use an OP carrier-backed number as an SMS channel
- Reply over SMS with
POST https://api.op.inc/v1/messages - Run dashboardless OP setup with OTP login
- Verify OP webhook signatures
- Restrict inbound SMS to allowed phone numbers
- Deduplicate repeated OP webhook deliveries
Example
You -> your OP number:
remind me tomorrow at 9 to check webhook logs
OpenClaw -> you:
Done. I will text you tomorrow at 9:00 AM.
Requirements
- OpenClaw installed
- An OP account / phone number
- Node.js 22+
cloudflaredor another public HTTPS tunnel for local webhook delivery
What gets installed
This repo is a native OpenClaw channel plugin. It provides:
openclaw.plugin.jsonchannel metadata forop- a runtime extension entry at
dist/index.js - a setup entry at
dist/setup-entry.js - an OP API client for auth, setup, messages, numbers, API keys, and webhooks
- a text-only outbound SMS adapter
- an OP webhook parser and signature verifier
- local tests for setup, signing, inbound parsing, allowlist behavior, dedupe, outbound sends, and runtime entry surfaces
Install
Install the plugin from GitHub:
openclaw plugins install JoshMayerr/openclaw-op-plugin --enable
Or install from the full Git URL:
openclaw plugins install https://github.com/JoshMayerr/openclaw-op-plugin.git --enable
Restart OpenClaw after install:
openclaw restart
Dashboardless setup
OP supports signup/login by OTP, so the plugin can configure OP without opening the dashboard. The only manual step is entering the OTP that OP texts you.
Setup order
-
Install and enable the plugin.
openclaw plugins install JoshMayerr/openclaw-op-plugin --enable -
Get the public webhook URL OP will call.
OP needs a public HTTPS URL that forwards to OpenClaw's local webhook endpoint.
The easiest option is Cloudflare Tunnel (
cloudflared):cloudflared tunnel --url http://localhost:<openclaw-port>Cloudflare prints a URL like:
https://example-random.trycloudflare.comAppend the OP webhook path:
https://example-random.trycloudflare.com/webhooks/opThat full URL is the value to pass as
--webhook-url. -
Run dashboardless OP setup. Use your personal phone number for OTP login, not necessarily the OP number.
openclaw plugin setup op --phone +14155551234 --webhook-url https://example-random.trycloudflare.com/webhooks/opThe setup flow will:
- call
POST /auth/startfor your phone number - prompt for the OTP OP texts you
- call
POST /auth/verify - use the returned
bootstrap_keyor create an API key through/console/api-keys - inspect your OP number through
/console/numbers/mine - optionally create the OP webhook through
/console/webhooks - return OpenClaw channel config for
channels.op
- call
-
Restart OpenClaw so the new channel config loads.
openclaw restart -
Send a test SMS to your OP number. OpenClaw should receive it through OP's webhook and reply over SMS.
If you use a temporary tunnel URL, it changes whenever the tunnel restarts. Re-run setup with the new --webhook-url or update the OP webhook whenever the public URL changes.
Configuration
OpenClaw channel config should look like:
{
"channels": {
"op": {
"apiKey": "op_live_...",
"apiBase": "https://api.op.inc",
"webhookSecret": "whsec_...",
"phoneNumber": "+14155550000",
"allowFrom": ["+14155551234"],
"allowAll": false,
"homeChannel": "+14155551234",
"webhookPath": "/webhooks/op"
}
}
}
The plugin can also read OP-style env vars for local development and migration from the Hermes plugin:
OP_API_KEY=op_live_...
OP_WEBHOOK_SECRET=...
OP_ALLOWED_NUMBERS=+14155551234
OP_HOME_CHANNEL=+14155551234
OP_WEBHOOK_PATH=/webhooks/op
OP_PHONE_NUMBER=+14155550000
Required:
| Config | Env var | Purpose |
|---|---|---|
apiKey | OP_API_KEY | OP bearer token. |
Strongly recommended:
| Config | Env var | Purpose |
|---|---|---|
webhookSecret | OP_WEBHOOK_SECRET | HMAC secret for OP webhook signature verification. |
allowFrom | OP_ALLOWED_NUMBERS | E.164 phone numbers allowed to chat with OpenClaw. |
Optional:
| Config | Env var | Default | Purpose |
|---|---|---|---|
apiBase | OP_API_BASE | https://api.op.inc | OP API base URL. |
phoneNumber | OP_PHONE_NUMBER | unset | Your OP number; used to ignore echoes. |
homeChannel | OP_HOME_CHANNEL | unset | Default SMS destination for proactive delivery. |
allowAll | OP_ALLOW_ALL_NUMBERS | false | Allow any inbound sender. Not recommended. |
webhookPath | OP_WEBHOOK_PATH | /webhooks/op | Webhook path OpenClaw should expose. |
Manual webhook setup
If you do not pass --webhook-url to setup, configure the webhook yourself in OP after setup.
The URL OP should call is your public HTTPS base URL plus webhookPath:
https://<your-public-host>/webhooks/op
For local development, get the public host from a tunnel:
cloudflared tunnel --url http://localhost:<openclaw-port>
Then use the printed https://...trycloudflare.com/webhooks/op URL in OP.
Default OP webhook events:
["message.received", "message.sent", "message.failed"]
Security model
- OP signs webhooks with
op-signature: t=<unix_ts>,v1=<hex_hmac>. - The plugin verifies
HMAC_SHA256(webhookSecret, timestamp + "." + raw_body). - Webhooks older/newer than 300 seconds are rejected.
- Duplicate deliveries are ignored using
op-delivery-idand message id fallback. - Inbound senders are ignored unless allowlisted or
allowAll=true. - Own-number echoes are ignored when
phoneNumberis configured. - SMS is treated as a text-only channel: no media, native edits, deletes, reactions, or real thread support.
OP API coverage
The TypeScript OP client currently includes:
| Method | Purpose |
|---|---|
authStart | Start OP OTP login with POST /auth/start. |
authVerify | Verify OTP with POST /auth/verify. |
getVerification | Inspect OTP status. |
listMyNumbers | List OP numbers owned by the account. |
listAvailableNumbers | List available OP numbers. |
createApiKey | Create an OP API key for a number. |
createWebhook | Create an OP webhook for a number. |
getNumber | Inspect the OP number attached to the runtime API key. |
sendMessage | Send outbound SMS with optional idempotency key. |
listMessages | List inbound/outbound messages with pagination. |
getMessage | Fetch a message by id. |
Unlike the Hermes plugin, this OpenClaw plugin does not yet register OP management tools for numbers, API keys, messages, and webhooks. The client methods are present so those tools can be added later.
Local development
npm install
npm test
npm run typecheck
npm run build
npm pack --dry-run
To smoke-test built entrypoints:
node -e "const m=await import('./dist/index.js'); const s=await import('./dist/setup-entry.js'); console.log({hasRegister: typeof m.register, channel: m.default.channel, setupChannel: s.default.channel})"
To test installation locally once an OpenClaw CLI/runtime is available:
openclaw plugins install file://$PWD --enable --force
openclaw restart
Status
v0.1.0 is a beta first pass. Unit tests cover OP client calls, signature verification, payload extraction, dedupe, setup config generation, allowlist behavior, outbound SMS receipts, package metadata, setup metadata, runtime registration, and webhook dispatch.
Known gaps:
- Host-level validation inside a real OpenClaw runtime has not been run yet.
- OP management tools are not registered as OpenClaw tools yet.
- Proactive/home-channel delivery depends on OpenClaw host integration.
- Webhook route mounting depends on the OpenClaw runtime API available at install time.