OpenPhone / Quo Hub

OpenPhone rebranded to Quo in 2025. The API base URL, webhook format, and HMAC signing remain unchanged — only the brand and docs URL changed. This hub covers the SMS and voice channel used primarily by the acquisitions pipeline (CH outreach Stages 1-4), plus inbound call routing. 34 active phone lines. Read this hub before modifying quo-handler-enhanced.js, changing webhook registration, or adjusting acquisitions SMS behavior. Owned by Henry Hill; primary consumer is the acquisitions agent and Aurora orchestrator.

⚠️ A2P 10DLC Cross-Impact Flag

A2P 10DLC repeat-denial on the Twilio channel also affects this channel’s compliance posture. Both Quo/OpenPhone SMS and Twilio SMS share the same TCPA compliance envelope. Until osil-twilio-10dlc-resubmission-2026-05-03 B14 (Henry signoff B14a pending), treat all conversational SMS tiers as operationally constrained. See twilio for the authoritative 10DLC compliance alert.

Quick reference

FieldValue
VendorQuo (formerly OpenPhone) — quo.com
URLhttps://api.openphone.com/v1 (unchanged post-rebrand)
KB docAPI · WEBHOOKS · CREDENTIALS
Auth methodAuthorization: {API_KEY} — raw key, NO Bearer prefix
Auth credentialop://Aurora/openphone/api-key
Cred-proxy portn/a (until B1-B6 ratified)
Webhook port:18792
Webhook handlerquo-handler-enhanced (quo-handler-enhanced.js)
Webhook auth✅ HMAC — HMAC-SHA256(secret, timestamp + "." + body); X-OpenPhone-Signature header
Webhook dedup tableprocessed_webhook_events (24h TTL)
Tunnel path (canonical)https://webhook.reri.co/webhook/openphone · alias: /webhook/quo
Tunnel path (fallback)https://srv1347501.tailb025a7.ts.net/webhook/openphone
Outbound API basehttps://api.openphone.com/v1
Rate limits10 req/s per API key
Rate-limit action429 → exponential backoff (3 retries), Discord ops alert
Active lines34 phone numbers
LineID requirement✅ REQUIRED — every outbound/inbound action must specify phoneNumberId (per feedback_quo_lineid_required)
SMS coverageUS + Canada (0.01 + country rate. MMS not supported in API.
Webhook registration⚠️ Dashboard-managed webhooks ONLY — API webhooks are invisible in dashboard; always register via app UI, not API
Process managersystemd openphone-webhook.service (NOT PM2 — moved off PM2 post-OOM cascade recovery)
Cost$0.01/SMS segment; voice per-minute (see Quo billing)
Backup/recoveryREST API backfill: node scripts/openphone-backfill.js --since=YYYY-MM-DD
Discord alert channelops
Staleness monitorscripts/ops/webhook-staleness-monitor.js — alerts ops if no inbound SMS for >3h during 7am-11pm PT
Drift cadenceWeekly (security-audit-funnel.timer)
Statusproduction

Components

  • webhooks/quo-handler-enhanced.js — main inbound webhook handler on :18792; routes call.ringing, call.completed, call.summary.completed, call.transcript.completed, message.received, message.delivered, contact.updated, contact.deleted
  • scripts/openphone-backfill.js — REST API backfill for gap recovery; run with --since=YYYY-MM-DD
  • scripts/ops/webhook-staleness-monitor.js — heartbeat monitor; runs every 30 min via cron; staleness log at /tmp/openclaw/webhook-staleness.log
  • systemd: openphone-webhook.service — process manager (migrated from PM2 during OOM cascade recovery); logs via journalctl --user -u openphone-webhook
  • Supabase tables: openphone_messages, openphone_calls, omni_events — primary write targets from handler

Known limitations (verified 2026-03-10 via live OpenAPI spec)

FeatureStatusNotes
note.created webhook❌ Does not existNo webhook fires when team member adds an internal note
Internal thread read❌ API write-onlyPOST /v1/conversations/{id}/notes works; no GET endpoint
Feedback via notes⚠️ Playwright onlyReading Henry’s notes requires browser automation (blocked on noVNC login)
Feedback channel (interim)✅ SMS from Henry’s numberHenry’s number (+16194033648) can send directives via SMS
message.updated❌ Not a webhook eventDelivery status only available via GET /v1/messages

Unverified fields (NEEDS VERIFICATION)

  • type field naming in webhook payload: docs show type: "callSummary" but subscription event is call.summary.completedverify via live test
  • callRoute + aiHandled fields in call.completed webhook: may only be available via GET /v1/calls, not webhook payload — verify via live test
  • contact.updated / contact.deleted events: listed in docs but not shown in official Quo webhook docs — verify via live test

How it’s used

  • Trigger: Inbound SMS fires message.received webhook → quo-handler-enhanced.js → Supabase write + acquisitions agent dispatch
  • Inbound call: call.ringingcall.completed → (optional) call.summary.completed + call.transcript.completed — all routed through handler → OpenClaw gateway → appropriate agent
  • Outbound: Acquisitions agent calls POST /v1/messages with phoneNumberId (required) + to + content — no auto-local-presence (unlike SalesMsg); must specify line explicitly
  • Agents involved: acquisitions agent (CH outreach SMS), Aurora (orchestration, thread routing), atlas agent (call routing decisions)
  • Failure mode: Staleness monitor fires if no inbound event for >3h during business hours → check journalctl --user -u openphone-webhook --since "1h" + verify Cloudflare Tunnel status
  • Backfill on gap: node scripts/openphone-backfill.js --since=YYYY-MM-DD recovers missed events via REST API
  • Success criteria: webhook events arrive at webhook.reri.co/webhook/openphone → handler writes to omni_events + channel-specific table → agent dispatched within 30s

Agents that touch this

  • _summary — primary consumer; CH outreach SMS via Quo lines
  • _summary — orchestrates thread routing, dispatches to sub-agents
  • _summary — call routing decisions; call.ringing handler escalation

Skills that invoke this

Plans that govern this

Feedback rules

KB / source docs

  • API — full API reference, auth, rate limits, endpoint inventory
  • WEBHOOKS — event types, HMAC signing, payload schemas, staleness monitor, backfill pattern
  • CREDENTIALS — API key location, rotation procedure

System maps

  • cloudflare — tunnel + WAF; canonical URL webhook.reri.co; FUNNEL-REGISTRY.md is authoritative
  • salesmsg — sibling handler on :18793
  • twilio — sibling handler on :18797; voice fallback path

Quo/OpenPhone handles inbound/outbound voice calls alongside Twilio. Both channels share the same TCPA/10DLC compliance envelope.

  • twilio — primary voice infrastructure; HMAC-SHA1 auth; 10DLC anchor
  • openphone-quo — this hub — Quo voice events (call.ringing, call.completed, summaries, transcripts)
  • livekit-deferred — real-time voice/video layer; deferred to OSIL Phase 6 (B10); not operational; do not build against until nemoclaw-audit-2026-05-03 B10 ships

Open issues / TODOs

  • Verify type field naming in live webhook payload (callSummary vs call.summary.completed) via live call test
  • Verify callRoute + aiHandled fields are present in call.completed webhook payload (or backfill-only)
  • Verify contact.updated / contact.deleted webhook events fire in practice
  • Confirm feedback_quo_lineid_required is enforced in ALL call sites in quo-handler-enhanced.js and all skills that POST to Quo API
  • Add Quo lines to cred-proxy rotation when B1-B6 ratified (see 1password)
  • B14 Henry signoff (10DLC resubmission) — track in osil-twilio-10dlc-resubmission-2026-05-03

Recent activity

  • 2026-05-03: hub created (W1-S2)
  • 2026-04-21: migrated to Cloudflare Tunnel canonical URL webhook.reri.co (Phase 8 complete)
  • 2026-04-13: WEBHOOKS.md last updated; confirmed HMAC signing pattern