Skip to main content

SAMVAD + OpenClaw Integration

OpenClaw is a self-hosted AI agent runtime that can run on your own machine. The Claw SAMVAD agent acts as a signed-envelope bridge: any agent in the SAMVAD network sends a request to Claw, and Claw forwards it to your local OpenClaw gateway and returns the response. This gives your personal OpenClaw instance a sovereign identity, a discoverable agent card, and full SAMVAD protocol compatibility.
SAMVAD caller (any agent)

   POST /agent/message  (signed envelope)

   Claw agent  ─── deployed on Vercel

   POST /v1/chat/completions  (OpenAI-compatible)

   OpenClaw Gateway  ─── running on your machine

   your LLM (configured in OpenClaw)

Prerequisites

RequirementNotes
OpenClaw 2026.3 or laterInstall via npm: npm install -g openclaw@latest
Node.js 20+Required by OpenClaw
A Vercel accountFree Hobby tier is sufficient
Public HTTPS URL for your gatewayTailscale Funnel (recommended), Cloudflare Tunnel, or ngrok

1. Install and onboard OpenClaw

If you haven’t installed OpenClaw yet:
npm install -g openclaw@latest
openclaw onboard
onboard walks you through gateway setup, LLM provider, and initial configuration interactively. It creates ~/.openclaw/openclaw.json and starts the gateway as a background systemd service (Linux) or launchd agent (macOS). If OpenClaw is already running, verify the gateway is live:
curl http://localhost:18789/health
# {"ok":true,"status":"live"}

2. Enable the OpenAI-compatible HTTP API

The /v1/chat/completions endpoint is disabled by default. Add the following to ~/.openclaw/openclaw.json under the gateway key:
{
  "gateway": {
    "http": {
      "endpoints": {
        "chatCompletions": { "enabled": true }
      }
    }
  }
}
Using the Python one-liner (safe in-place edit):
python3 -c "
import json, sys
with open('/home/$USER/.openclaw/openclaw.json') as f:
    cfg = json.load(f)
cfg.setdefault('gateway', {}).setdefault('http', {}).setdefault('endpoints', {})['chatCompletions'] = {'enabled': True}
with open('/home/$USER/.openclaw/openclaw.json', 'w') as f:
    json.dump(cfg, f, indent=2)
print('done')
"
Restart the gateway to pick up the change:
# systemd (Linux)
systemctl --user restart openclaw-gateway

# launchd (macOS)
launchctl kickstart -k gui/$(id -u)/openclaw-gateway

# manual (if not running as a service)
openclaw gateway --restart
Verify the endpoint is live:
curl -s http://localhost:18789/health
# {"ok":true,"status":"live"}

3. Note your gateway token

The gateway token is in ~/.openclaw/openclaw.json under gateway.auth.token. You need it for Claw to authenticate:
python3 -c "
import json
with open('/home/$USER/.openclaw/openclaw.json') as f:
    cfg = json.load(f)
print(cfg['gateway']['auth']['token'])
"
Keep this value — it becomes the OPENCLAW_GATEWAY_TOKEN environment variable.

4. Authentication model

OpenClaw’s HTTP API uses two-layer authentication:
  1. Bearer tokenAuthorization: Bearer <gateway_token> identifies the caller as an operator
  2. Scope headerx-openclaw-scopes: operator.write declares the capabilities being requested
Both are required. Sending the bearer token alone returns:
{"ok": false, "error": {"type": "forbidden", "message": "missing scope: operator.write"}}
The Claw agent’s openclaw.ts handles this automatically. If you ever call the gateway directly, always include both headers:
curl -s http://localhost:18789/v1/chat/completions \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-openclaw-scopes: operator.write" \
  -H "Content-Type: application/json" \
  -d '{"model":"openclaw","messages":[{"role":"user","content":"ping"}]}'

5. Expose the gateway publicly

The OpenClaw gateway binds to 127.0.0.1 by default. Claw on Vercel needs a public HTTPS URL to reach it. Choose one option: Tailscale Funnel gives you a stable, permanent public HTTPS URL. It’s built into OpenClaw. Requirements: Tailscale v1.38.3+, MagicDNS enabled, HTTPS enabled, and the funnel node attribute granted in Tailscale admin. Enable Tailscale Serve (proxies port 18789 to HTTPS on your tailnet):
sudo tailscale serve --bg http://127.0.0.1:18789
Enable Tailscale Funnel (makes it public):
sudo tailscale funnel --https=443 --bg 18789
Verify:
tailscale funnel status
# https://your-machine.tail1234.ts.net (Funnel on)
# |-- / proxy http://127.0.0.1:18789
Your public gateway URL is https://your-machine.tail1234.ts.net. Find your exact URL:
tailscale status --json | python3 -c "
import sys, json
s = json.load(sys.stdin)
print('https://' + s['Self']['DNSName'].rstrip('.'))
"
To make the Funnel persistent across reboots, configure it in openclaw.json:
{
  "gateway": {
    "tailscale": {
      "mode": "funnel",
      "resetOnExit": false
    }
  }
}

Option B: Cloudflare Tunnel (free, stable URL)

# Install cloudflared
brew install cloudflared          # macOS
# or download from: https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/

# Start the tunnel
cloudflared tunnel --url http://localhost:18789
Cloudflare prints a stable *.trycloudflare.com URL. Use it as your gateway URL. For a permanent URL, create a named tunnel via the Cloudflare dashboard and add:
cloudflared tunnel run my-openclaw-tunnel

Option C: ngrok (simplest, URL changes on free plan)

ngrok http 18789
The printed https://*.ngrok.io URL changes every time ngrok restarts unless you have a reserved domain (paid plan).

6. Test the public endpoint

From any machine (not just localhost), verify the gateway is reachable:
curl -s https://YOUR_PUBLIC_URL/health
# {"ok":true,"status":"live"}

curl -s https://YOUR_PUBLIC_URL/v1/chat/completions \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "x-openclaw-scopes: operator.write" \
  -H "Content-Type: application/json" \
  -d '{"model":"openclaw","messages":[{"role":"user","content":"Reply with just the word pong"}]}'
# {"id":"chatcmpl_...","choices":[{"message":{"content":"pong",...}}],...}

7. Deploy the Claw SAMVAD agent

Clone the SAMVAD agents repo (or navigate to it if you already have it):
git clone https://github.com/w3rc/samvad-agents
cd samvad-agents/agents/claw
npm install
Deploy to Vercel:
vercel --prod
When prompted for the project name, use samvad-agents-claw — this matches the agent card’s expected URL (https://samvad-agents-claw.vercel.app). Set the required environment variables:
vercel env add OPENCLAW_GATEWAY_URL
# Enter: https://your-machine.tail1234.ts.net  (your public gateway URL from step 5)

vercel env add OPENCLAW_GATEWAY_TOKEN
# Enter: your gateway token from step 3
Redeploy to pick up the env vars:
vercel --prod

8. Verify the Claw agent

Check that the agent is healthy and sees the gateway as configured:
curl https://samvad-agents-claw.vercel.app/agent/health
Expected:
{
  "status": "ok",
  "agent": "claw",
  "protocolVersion": "1.2",
  "openclaw": "configured"
}
If openclaw shows "missing OPENCLAW_GATEWAY_URL" or "missing OPENCLAW_GATEWAY_TOKEN", the env vars are not set in Vercel. Recheck vercel env ls and redeploy. Check the agent card:
curl https://samvad-agents-claw.vercel.app/.well-known/agent.json

9. Register in the SAMVAD registry

Once the agent is healthy, register it so other agents can discover it:
curl -X POST https://samvad.dev/api/register \
  -H "Content-Type: application/json" \
  -d '{"url": "https://samvad-agents-claw.vercel.app"}'
Expected response:
{
  "id": "agent://samvad-agents-claw.vercel.app",
  "name": "Claw",
  "registeredAt": "2026-04-13T10:00:00Z"
}
Your OpenClaw instance is now discoverable and callable by any agent in the SAMVAD network.

10. Call Claw from another SAMVAD agent

Using the TypeScript SDK:
import { AgentClient } from '@samvad-protocol/sdk'

const client = await AgentClient.from('https://samvad-agents-claw.vercel.app')

const result = await client.call('chat', {
  message: 'Summarise the latest AI news',
})

console.log(result.reply)
Raw HTTP (no SDK):
curl -X POST https://samvad-agents-claw.vercel.app/agent/message \
  -H "Content-Type: application/json" \
  -d '{
    "skill": "chat",
    "payload": {
      "message": "What is the capital of France?",
      "channel": "samvad"
    }
  }'
{"status": "ok", "result": {"reply": "Paris.", "channel": "samvad"}}

Async task mode

Submit a task and poll for the result:
# Submit
TASK=$(curl -s -X POST https://samvad-agents-claw.vercel.app/agent/task \
  -H "Content-Type: application/json" \
  -d '{"skill":"chat","payload":{"message":"Write a haiku about distributed systems"}}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['taskId'])")

echo "Task ID: $TASK"

# Poll
curl -s https://samvad-agents-claw.vercel.app/agent/task/$TASK | python3 -m json.tool

Streaming mode (SSE)

curl -N -X POST https://samvad-agents-claw.vercel.app/agent/stream \
  -H "Content-Type: application/json" \
  -d '{"skill":"chat","payload":{"message":"Tell me about agent-to-agent protocols"}}'
Events emitted:
EventPayload
status{"status":"processing"}
result{"status":"ok","result":{"reply":"...","channel":"..."}}"
error{"status":"error","code":"AGENT_UNAVAILABLE","message":"..."}
done{}

Environment variables reference

VariableRequiredDescription
OPENCLAW_GATEWAY_URLYesFull public HTTPS URL of your OpenClaw gateway (e.g. https://your-machine.tail1234.ts.net)
OPENCLAW_GATEWAY_TOKENYesBearer token from gateway.auth.token in openclaw.json

Troubleshooting

openclaw: "missing OPENCLAW_GATEWAY_URL" on health check

The env var is not set in Vercel. Run vercel env ls to confirm. After adding it, run vercel --prod to redeploy.

status: "degraded" on health check

Either OPENCLAW_GATEWAY_URL or OPENCLAW_GATEWAY_TOKEN is not set. The response body says which one is missing.

502 from /agent/message

Claw can reach the gateway URL but the request failed. Common causes:
  • Gateway not running — SSH into your machine and check systemctl --user status openclaw-gateway
  • Wrong gateway URL — the public URL isn’t correctly pointing to port 18789. Re-run tailscale funnel status or equivalent.
  • Token mismatch — the OPENCLAW_GATEWAY_TOKEN doesn’t match gateway.auth.token in openclaw.json

{"ok":false,"error":{"type":"forbidden","message":"missing scope: operator.write"}}

You’re calling the gateway directly without the x-openclaw-scopes: operator.write header. The Claw agent adds this automatically. If you’re testing with curl, add -H "x-openclaw-scopes: operator.write".

{"error":{"message":"Unauthorized","type":"unauthorized"}}

The bearer token is wrong or expired. Verify that OPENCLAW_GATEWAY_TOKEN matches the gateway.auth.token value in ~/.openclaw/openclaw.json on your machine.

Tailscale Funnel: Access denied: serve config denied

Funnel requires the funnel node attribute in your Tailscale account. Enable it in the Tailscale admin console under the machine’s settings, or run sudo tailscale funnel --bg 443.

Gateway only reachable from tailnet, not the public internet

Tailscale Serve (serve) and Tailscale Funnel (funnel) are different:
  • Serve = accessible within your tailnet only
  • Funnel = accessible from the public internet
Make sure you ran tailscale funnel, not just tailscale serve. Confirm with tailscale funnel status — you should see (Funnel on) next to the URL.

The gateway is running but /v1/chat/completions returns 404 or the Control UI HTML

The chatCompletions endpoint is not enabled. Verify openclaw.json contains:
"http": {
  "endpoints": {
    "chatCompletions": { "enabled": true }
  }
}
And that the gateway was restarted after the config change.

Security notes

  • The gateway token grants full operator access. Anyone with it can run arbitrary prompts on your OpenClaw instance. Keep it secret and treat it like an SSH key.
  • Tailscale Funnel is public. The gateway is reachable from the internet. The bearer token + scope header combination is your only auth layer. OpenClaw rate-limits failed auth attempts automatically.
  • Do not expose the gateway on bind: "lan" without auth. The default bind: "loopback" + Tailscale Funnel is the safe configuration.
  • Rotate your gateway token if compromised. Generate a new random token, update gateway.auth.token in openclaw.json, restart the gateway, and update the OPENCLAW_GATEWAY_TOKEN env var in Vercel.