diff --git a/docs/plugins/google-meet.md b/docs/plugins/google-meet.md index a7e90d1defd..0ffe53dea17 100644 --- a/docs/plugins/google-meet.md +++ b/docs/plugins/google-meet.md @@ -92,6 +92,16 @@ scripts or machine-readable output. Use `--transport chrome`, `--transport chrome-node`, or `--transport twilio` to preflight a specific transport before an agent tries it. +For Twilio, always preflight the transport explicitly when the default transport +is Chrome: + +```bash +openclaw googlemeet setup --transport twilio +``` + +That catches missing `voice-call` wiring, Twilio credentials, or unreachable +webhook exposure before the agent tries to dial the meeting. + Join a meeting: ```bash @@ -1310,10 +1320,52 @@ exposure, or when `publicUrl` points at loopback or private network space. Set `plugins.entries.voice-call.config.publicUrl` to the public provider URL or configure a `voice-call` tunnel/Tailscale exposure. +Loopback and private URLs are not valid for carrier callbacks. Do not use +`localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, +`192.168.x`, `169.254.x`, `fc00::/7`, or `fd00::/8` as `publicUrl`. + +For a stable public URL: + +```json5 +{ + plugins: { + entries: { + "voice-call": { + enabled: true, + config: { + provider: "twilio", + fromNumber: "+15550001234", + publicUrl: "https://voice.example.com/voice/webhook", + }, + }, + }, + }, +} +``` + +For local development, use a tunnel or Tailscale exposure instead of a private +host URL: + +```json5 +{ + plugins: { + entries: { + "voice-call": { + config: { + tunnel: { provider: "ngrok" }, + // or + tailscale: { mode: "funnel", path: "/voice/webhook" }, + }, + }, + }, + }, +} +``` + Then restart or reload the Gateway and run: ```bash -openclaw googlemeet setup +openclaw googlemeet setup --transport twilio openclaw voicecall setup openclaw voicecall smoke ``` @@ -1346,6 +1398,24 @@ openclaw googlemeet join https://meet.google.com/abc-defg-hij \ Use leading `w` or commas in `--dtmf-sequence` if the provider needs a pause before entering the PIN. +If the phone call is created but the Meet roster never shows the dial-in +participant: + +- Run `openclaw voicecall status --call-id ` and confirm the call is still + active. +- Run `openclaw voicecall tail` and check that Twilio webhooks are arriving at + the Gateway. +- Re-run `openclaw googlemeet setup --transport twilio`; a green setup check is + required but does not prove the meeting PIN sequence is correct. +- Confirm the dial-in number belongs to the same Meet invitation and region as + the PIN. +- Increase the leading pauses in `--dtmf-sequence` if Meet answers slowly, for + example `wwww123456#`. + +If webhooks do not arrive, debug the Voice Call plugin first: the provider must +reach `plugins.entries.voice-call.config.publicUrl` or the configured tunnel. +See [Voice call troubleshooting](/plugins/voice-call#troubleshooting). + ## Notes Google Meet's official media API is receive-oriented, so speaking into a Meet diff --git a/docs/plugins/voice-call.md b/docs/plugins/voice-call.md index b0af9fdc592..2adbab620d9 100644 --- a/docs/plugins/voice-call.md +++ b/docs/plugins/voice-call.md @@ -646,6 +646,139 @@ This repo ships a matching skill doc at `skills/voice-call/SKILL.md`. | `voicecall.end` | `callId` | | `voicecall.status` | `callId` | +## Troubleshooting + +### Setup fails webhook exposure + +Run setup from the same environment that runs the Gateway: + +```bash +openclaw voicecall setup +openclaw voicecall setup --json +``` + +For `twilio`, `telnyx`, and `plivo`, `webhook-exposure` must be green. A +configured `publicUrl` still fails when it points at local or private network +space, because the carrier cannot call back into those addresses. Do not use +`localhost`, `127.0.0.1`, `0.0.0.0`, `10.x`, `172.16.x`-`172.31.x`, +`192.168.x`, `169.254.x`, `fc00::/7`, or `fd00::/8` as `publicUrl`. + +Use one public exposure path: + +```json5 +{ + plugins: { + entries: { + "voice-call": { + config: { + publicUrl: "https://voice.example.com/voice/webhook", + // or + tunnel: { provider: "ngrok" }, + // or + tailscale: { mode: "funnel", path: "/voice/webhook" }, + }, + }, + }, + }, +} +``` + +After changing config, restart or reload the Gateway, then run: + +```bash +openclaw voicecall setup +openclaw voicecall smoke +``` + +`voicecall smoke` is a dry run unless you pass `--yes`. + +### Provider credentials fail + +Check the selected provider and the required credential fields: + +- Twilio: `twilio.accountSid`, `twilio.authToken`, and `fromNumber`, or + `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, and `TWILIO_FROM_NUMBER`. +- Telnyx: `telnyx.apiKey`, `telnyx.connectionId`, `telnyx.publicKey`, and + `fromNumber`. +- Plivo: `plivo.authId`, `plivo.authToken`, and `fromNumber`. + +Credentials must exist on the Gateway host. Editing a local shell profile does +not affect an already running Gateway until it restarts or reloads its +environment. + +### Calls start but provider webhooks do not arrive + +Confirm the provider console points at the exact public webhook URL: + +```text +https://voice.example.com/voice/webhook +``` + +Then inspect runtime state: + +```bash +openclaw voicecall status --call-id +openclaw voicecall tail +``` + +Common causes: + +- `publicUrl` points at a different path than `serve.path`. +- The tunnel URL changed after the Gateway started. +- A proxy forwards the request but strips or rewrites host/proto headers. +- Firewall or DNS routes the public hostname somewhere other than the Gateway. +- The Gateway was restarted without the Voice Call plugin enabled. + +When a reverse proxy or tunnel is in front of the Gateway, set +`webhookSecurity.allowedHosts` to the public hostname, or use +`webhookSecurity.trustedProxyIPs` for a known proxy address. Use +`webhookSecurity.trustForwardingHeaders` only when the proxy boundary is under +your control. + +### Signature verification fails + +Provider signatures are checked against the public URL OpenClaw reconstructs +from the incoming request. If signatures fail: + +- Confirm the provider webhook URL exactly matches `publicUrl`, including + scheme, host, and path. +- For ngrok free-tier URLs, update `publicUrl` when the tunnel hostname changes. +- Ensure the proxy preserves the original host and proto headers, or configure + `webhookSecurity.allowedHosts`. +- Do not enable `skipSignatureVerification` outside local testing. + +### Google Meet Twilio joins fail + +Google Meet uses this plugin for Twilio dial-in joins. First verify Voice Call: + +```bash +openclaw voicecall setup +openclaw voicecall smoke --to "+15555550123" +``` + +Then verify the Google Meet transport explicitly: + +```bash +openclaw googlemeet setup --transport twilio +``` + +If Voice Call is green but the Meet participant never joins, check the Meet +dial-in number, PIN, and `--dtmf-sequence`. The phone call can be healthy while +the meeting rejects or ignores an incorrect DTMF sequence. + +### Realtime call has no speech + +Confirm only one audio mode is enabled. `realtime.enabled` and +`streaming.enabled` cannot both be true. + +For realtime Twilio calls, also verify: + +- A realtime provider plugin is loaded and registered. +- `realtime.provider` is unset or names a registered provider. +- The provider API key is available to the Gateway process. +- `openclaw voicecall tail` shows the media stream accepted and realtime + provider readiness before the initial greeting. + ## Related - [Talk mode](/nodes/talk)