
Build Zoom Phone Integration
Wire Zoom Phone (Smart Embed, webhooks, REST) into a CRM or agent UI with OAuth kept on the server and call lifecycle persisted safely.
Overview
build-zoom-phone-integration is an agent skill for the Build phase that documents Zoom Phone Smart Embed, webhook, and REST patterns for CRM-style apps with server-side OAuth.
Install
npx skills add https://github.com/anthropics/knowledge-work-plugins --skill build-zoom-phone-integrationWhat is this skill?
- 7-step lifecycle from provision through post-call notes and ongoing deprecation handling
- Smart Embed postMessage flow: zp-init-config, zp-make-call, zp-input-sms, and call/SMS event streams
- Server-only OAuth with Zoom Phone REST for call history, handling, and contacts
- Webhook endpoint pattern for phone.* events reconciled to callId snapshots
- Migration-safe adapter layer with centralized endpoint constants and tolerant enum expansion
- 7-step lifecycle workflow from provision through operate
Adoption & trust: 833 installs on skills.sh; 19.6k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You need in-app calling and SMS via Zoom Phone but lack a clear split between iframe events, backend APIs, and durable call records.
Who is it for?
Solo builders shipping a SaaS CRM or support console that must embed Zoom Phone and sync call history on the server.
Skip if: Teams only choosing Zoom app types without writing code—use zoom-general first—or products that do not use Zoom Phone at all.
When should I use this skill?
Implementing or refactoring Zoom Phone Smart Embed, REST reconciliation, or phone.* webhooks in a SaaS app.
What do I get? / Deliverables
You get a reference architecture and lifecycle checklist so embed events, REST reconciliation, and webhooks persist consistent call state after each engagement.
- Architecture diagram-aligned implementation
- Event adapter and callId persistence model
- Post-call notes and reconciliation flow
Recommended Skills
Journey fit
Canonical shelf is Build → integrations because the skill documents end-to-end Zoom Phone embedding, API reconciliation, and webhook handling for product code. Subphase integrations matches third-party telephony embeds, event bridges, and backend API layers—not generic frontend polish alone.
How it compares
Procedural integration blueprint for Zoom Phone, not a generic OAuth tutorial or Meeting SDK-only guide.
Common Questions / FAQ
Who is build-zoom-phone-integration for?
Indie and solo developers building web apps that embed Zoom Phone Smart Embed and need server-side OAuth plus webhook persistence.
When should I use build-zoom-phone-integration?
During Build when wiring telephony into your product: after Zoom Phone is provisioned, while designing the event bridge, and when hardening post-call CRM fields and API drift handling.
Is build-zoom-phone-integration safe to install?
Review the Security Audits panel on this Prism page and treat OAuth secrets and webhook verification as your responsibility—the skill describes patterns, not audited production code.
Workflow Chain
Requires first: skill anthropics knowledge work plugins zoom gen
SKILL.md
READMESKILL.md - Build Zoom Phone Integration
# Zoom Phone Architecture and Lifecycle ## Architecture ```text User/Agent UI | | (A) Smart Embed postMessage events v Smart Embed Iframe (applications.zoom.us) | | event stream + call controls v CRM Web App (event bridge + UI state) | | OAuth token on server only v Backend API Layer |\ | \-- Zoom Phone REST APIs (call history, call handling, contacts) | \---- Webhook endpoint (phone.* events) ``` ## Lifecycle Workflow 1. Provision: - Account has Zoom Phone and optional SMS enablement. 2. Authorize: - OAuth app installed and scoped for required Phone operations. 3. Initialize UI: - Load Smart Embed iframe/script. - Wait for `onZoomPhoneIframeApiReady`. - Send `zp-init-config` and register event handlers. 4. Engage: - Start calls/SMS via `zp-make-call` or `zp-input-sms`. - Receive events (`zp-call-*`, `zp-sms-log-event`, optional AI/contact/notes events). 5. Persist: - Save event snapshots keyed by `callId`. - Reconcile to call history/call element records after completion. 6. Post-call: - Save call notes/disposition and optional recording/voicemail links. 7. Operate: - Track deprecations and apply endpoint/event mapping updates. ## Version Drift Strategy - Normalize inbound payloads in one adapter layer. - Keep endpoint constants centralized by version target. - Feature-flag optional payload fields. - Keep webhook + Smart Embed event handlers tolerant to added fields and enum expansion. # Phone API Service Pattern (Migration-Safe) ## Pattern goals - Isolate OAuth token usage to server code. - Support current call history/call element model. - Keep compatibility with old payload fields while migrating. ## Service example ```javascript export async function getCallHistory(accessToken, from, to) { const qs = new URLSearchParams({ from, to }).toString(); const res = await fetch(`https://api.zoom.us/v2/phone/call_history?${qs}`, { headers: { Authorization: `Bearer ${accessToken}` }, }); if (!res.ok) throw new Error(`call_history failed: ${res.status}`); const data = await res.json(); // Normalize v2/v3 style for downstream code. return (data.call_history || data.call_logs || []).map((row) => ({ callHistoryUuid: row.call_history_uuid || row.id, callId: row.call_id, raw: row, })); } export async function getCallElement(accessToken, callElementId) { const res = await fetch(`https://api.zoom.us/v2/phone/call_element/${callElementId}`, { headers: { Authorization: `Bearer ${accessToken}` }, }); if (!res.ok) throw new Error(`call_element failed: ${res.status}`); return res.json(); } ``` ## Operational notes - Add explicit logging when fallback fields (`call_logs`, `call_path`) are encountered. - Remove fallback path once migration is complete. # Smart Embed postMessage Bridge Pattern ## Why this pattern Smart Embed event/control flow is `window.postMessage` based. Reliability depends on strict initialization order and origin validation. ## Pattern ```javascript const ZOOM_ORIGIN = 'https://applications.zoom.us'; const iframe = document.querySelector('#zoom-embeddable-phone-iframe'); function initSmartEmbed(config) { iframe?.contentWindow?.postMessage({ type: 'zp-init-config', data: config, }, ZOOM_ORIGIN); } function makeCall(number, callerId) { iframe?.contentWindow?.postMessage({ type: 'zp-make-call', data: { number, callerId, autoDial: true }, }, ZOOM_ORIGIN); } window.addEventListener('message', (event) => { if (event.origin !== ZOOM_ORIGIN) return; const payload = event.data; if (!payload?.type) return; switch (payload.type) { case 'zp-call-ringing-event': case 'zp-call-connected-event': case 'zp-call-ended-event': case 'zp-call-log-completed-event': handlePhoneEvent(payload); break; default: break; } }); ``` ## Operational notes - Call APIs only after iframe readiness callback. - Persist `event.id` (if present) for idempotency. - Keep event dispatcher toleran