wxcli 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (413) hide show
  1. wxcli/__init__.py +4 -0
  2. wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
  3. wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
  4. wxcli/_playbook/.claude/rules/cleanup.md +29 -0
  5. wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
  6. wxcli/_playbook/.claude/rules/org-health.md +14 -0
  7. wxcli/_playbook/.claude/settings.json +8 -0
  8. wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
  9. wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
  10. wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
  11. wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
  12. wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
  13. wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
  14. wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
  15. wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
  16. wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
  17. wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
  18. wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
  19. wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
  20. wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
  21. wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
  22. wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
  23. wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
  24. wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
  25. wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
  26. wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
  27. wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
  28. wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
  29. wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
  30. wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
  31. wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
  32. wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
  33. wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
  34. wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
  35. wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
  36. wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
  37. wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
  38. wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
  39. wxcli/_playbook/CLAUDE.md +373 -0
  40. wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
  41. wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
  42. wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
  43. wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
  44. wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
  45. wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
  46. wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
  47. wxcli/_playbook/docs/reference/admin-partner.md +357 -0
  48. wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
  49. wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
  50. wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
  51. wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
  52. wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
  53. wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
  54. wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
  55. wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
  56. wxcli/_playbook/docs/reference/authentication.md +965 -0
  57. wxcli/_playbook/docs/reference/call-control.md +1205 -0
  58. wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
  59. wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
  60. wxcli/_playbook/docs/reference/call-routing.md +2304 -0
  61. wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
  62. wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
  63. wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
  64. wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
  65. wxcli/_playbook/docs/reference/devices-core.md +1869 -0
  66. wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
  67. wxcli/_playbook/docs/reference/devices-platform.md +467 -0
  68. wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
  69. wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
  70. wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
  71. wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
  72. wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
  73. wxcli/_playbook/docs/reference/meetings-content.md +473 -0
  74. wxcli/_playbook/docs/reference/meetings-core.md +903 -0
  75. wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
  76. wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
  77. wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
  78. wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
  79. wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
  80. wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
  81. wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
  82. wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
  83. wxcli/_playbook/docs/reference/provisioning.md +1366 -0
  84. wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
  85. wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
  86. wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
  87. wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
  88. wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
  89. wxcli/_version.py +24 -0
  90. wxcli/auth.py +137 -0
  91. wxcli/commands/__init__.py +0 -0
  92. wxcli/commands/_registry.py +181 -0
  93. wxcli/commands/activation_email.py +103 -0
  94. wxcli/commands/admin_recordings.py +585 -0
  95. wxcli/commands/analytics.py +105 -0
  96. wxcli/commands/announcement_playlists.py +219 -0
  97. wxcli/commands/announcements.py +519 -0
  98. wxcli/commands/archive_users.py +36 -0
  99. wxcli/commands/attachment_actions.py +60 -0
  100. wxcli/commands/audit_events.py +83 -0
  101. wxcli/commands/authorizations.py +113 -0
  102. wxcli/commands/auto_attendant.py +642 -0
  103. wxcli/commands/broadworks_billing_reports.py +126 -0
  104. wxcli/commands/broadworks_enterprises.py +160 -0
  105. wxcli/commands/broadworks_subscribers.py +319 -0
  106. wxcli/commands/broadworks_workspaces.py +108 -0
  107. wxcli/commands/call_controls.py +1304 -0
  108. wxcli/commands/call_park.py +494 -0
  109. wxcli/commands/call_pickup.py +229 -0
  110. wxcli/commands/call_queue.py +1878 -0
  111. wxcli/commands/call_recording.py +707 -0
  112. wxcli/commands/call_routing.py +1610 -0
  113. wxcli/commands/call_settings_for_me_phase_5.py +212 -0
  114. wxcli/commands/caller_reputation.py +169 -0
  115. wxcli/commands/calling_service.py +305 -0
  116. wxcli/commands/cc_address_book.py +770 -0
  117. wxcli/commands/cc_agent_greetings.py +242 -0
  118. wxcli/commands/cc_agent_summaries.py +39 -0
  119. wxcli/commands/cc_agent_wellbeing.py +216 -0
  120. wxcli/commands/cc_agents.py +425 -0
  121. wxcli/commands/cc_ai_assistant.py +55 -0
  122. wxcli/commands/cc_ai_feature.py +294 -0
  123. wxcli/commands/cc_audio_files.py +149 -0
  124. wxcli/commands/cc_auto_csat.py +311 -0
  125. wxcli/commands/cc_aux_code.py +458 -0
  126. wxcli/commands/cc_business_hour.py +353 -0
  127. wxcli/commands/cc_call_monitoring.py +228 -0
  128. wxcli/commands/cc_callbacks.py +194 -0
  129. wxcli/commands/cc_campaign.py +212 -0
  130. wxcli/commands/cc_captures.py +39 -0
  131. wxcli/commands/cc_contact_list.py +169 -0
  132. wxcli/commands/cc_contact_number.py +295 -0
  133. wxcli/commands/cc_data_sources.py +235 -0
  134. wxcli/commands/cc_desktop_layout.py +380 -0
  135. wxcli/commands/cc_desktop_profile.py +322 -0
  136. wxcli/commands/cc_dial_number.py +511 -0
  137. wxcli/commands/cc_dial_plan.py +347 -0
  138. wxcli/commands/cc_dnc.py +101 -0
  139. wxcli/commands/cc_entry_point.py +545 -0
  140. wxcli/commands/cc_ewt.py +51 -0
  141. wxcli/commands/cc_flow.py +477 -0
  142. wxcli/commands/cc_global_vars.py +430 -0
  143. wxcli/commands/cc_holiday_list.py +335 -0
  144. wxcli/commands/cc_journey.py +1261 -0
  145. wxcli/commands/cc_legacy_flows.py +49 -0
  146. wxcli/commands/cc_multimedia_profile.py +436 -0
  147. wxcli/commands/cc_notification.py +51 -0
  148. wxcli/commands/cc_outdial_ani.py +604 -0
  149. wxcli/commands/cc_overrides.py +341 -0
  150. wxcli/commands/cc_queue.py +1083 -0
  151. wxcli/commands/cc_queue_stats.py +55 -0
  152. wxcli/commands/cc_realtime.py +51 -0
  153. wxcli/commands/cc_resource_collection.py +312 -0
  154. wxcli/commands/cc_search.py +46 -0
  155. wxcli/commands/cc_site.py +400 -0
  156. wxcli/commands/cc_skill.py +350 -0
  157. wxcli/commands/cc_skill_profile.py +289 -0
  158. wxcli/commands/cc_subscriptions.py +426 -0
  159. wxcli/commands/cc_summaries.py +130 -0
  160. wxcli/commands/cc_tasks.py +844 -0
  161. wxcli/commands/cc_team.py +325 -0
  162. wxcli/commands/cc_user_profiles.py +349 -0
  163. wxcli/commands/cc_users.py +701 -0
  164. wxcli/commands/cc_work_types.py +363 -0
  165. wxcli/commands/cdr.py +89 -0
  166. wxcli/commands/classifications.py +38 -0
  167. wxcli/commands/cleanup.py +1427 -0
  168. wxcli/commands/client_settings.py +72 -0
  169. wxcli/commands/conference.py +328 -0
  170. wxcli/commands/configure.py +72 -0
  171. wxcli/commands/converged_recordings.py +347 -0
  172. wxcli/commands/converged_recordings_export.py +310 -0
  173. wxcli/commands/cq_playlists.py +42 -0
  174. wxcli/commands/cucm.py +2794 -0
  175. wxcli/commands/cucm_config.py +129 -0
  176. wxcli/commands/customer_assist.py +373 -0
  177. wxcli/commands/data_sources.py +227 -0
  178. wxcli/commands/dect_devices.py +787 -0
  179. wxcli/commands/device_configurations.py +77 -0
  180. wxcli/commands/device_dynamic_settings.py +320 -0
  181. wxcli/commands/device_settings.py +1489 -0
  182. wxcli/commands/devices.py +280 -0
  183. wxcli/commands/domains.py +142 -0
  184. wxcli/commands/ecm.py +178 -0
  185. wxcli/commands/emergency_services.py +827 -0
  186. wxcli/commands/events.py +83 -0
  187. wxcli/commands/external_voicemail.py +52 -0
  188. wxcli/commands/groups.py +206 -0
  189. wxcli/commands/guest_management.py +76 -0
  190. wxcli/commands/hds.py +340 -0
  191. wxcli/commands/hot_desk.py +67 -0
  192. wxcli/commands/hot_desking_members.py +118 -0
  193. wxcli/commands/hot_desking_portal.py +124 -0
  194. wxcli/commands/hunt_group.py +577 -0
  195. wxcli/commands/hybrid_clusters.py +71 -0
  196. wxcli/commands/hybrid_connectors.py +67 -0
  197. wxcli/commands/identity_org.py +159 -0
  198. wxcli/commands/init_playbook.py +155 -0
  199. wxcli/commands/licenses.py +106 -0
  200. wxcli/commands/live_monitoring.py +40 -0
  201. wxcli/commands/location_call_handling.py +577 -0
  202. wxcli/commands/location_schedules.py +341 -0
  203. wxcli/commands/location_settings.py +1297 -0
  204. wxcli/commands/location_voicemail.py +494 -0
  205. wxcli/commands/locations.py +336 -0
  206. wxcli/commands/meeting_captions.py +110 -0
  207. wxcli/commands/meeting_chats.py +63 -0
  208. wxcli/commands/meeting_invitees.py +234 -0
  209. wxcli/commands/meeting_messages.py +28 -0
  210. wxcli/commands/meeting_participants.py +278 -0
  211. wxcli/commands/meeting_polls.py +111 -0
  212. wxcli/commands/meeting_preferences.py +515 -0
  213. wxcli/commands/meeting_qa.py +78 -0
  214. wxcli/commands/meeting_qualities.py +43 -0
  215. wxcli/commands/meeting_reports.py +101 -0
  216. wxcli/commands/meeting_session_types.py +105 -0
  217. wxcli/commands/meeting_site.py +57 -0
  218. wxcli/commands/meeting_slido.py +44 -0
  219. wxcli/commands/meeting_summaries.py +92 -0
  220. wxcli/commands/meeting_tracking_codes.py +233 -0
  221. wxcli/commands/meeting_transcripts.py +230 -0
  222. wxcli/commands/meetings.py +1997 -0
  223. wxcli/commands/memberships.py +164 -0
  224. wxcli/commands/messages.py +213 -0
  225. wxcli/commands/mode_management.py +244 -0
  226. wxcli/commands/my_call_settings.py +3577 -0
  227. wxcli/commands/numbers.py +405 -0
  228. wxcli/commands/operating_modes.py +410 -0
  229. wxcli/commands/org_contacts.py +284 -0
  230. wxcli/commands/org_health_cli.py +55 -0
  231. wxcli/commands/org_settings.py +71 -0
  232. wxcli/commands/organizations.py +83 -0
  233. wxcli/commands/paging_group.py +257 -0
  234. wxcli/commands/partner_admins.py +141 -0
  235. wxcli/commands/partner_reports.py +188 -0
  236. wxcli/commands/partner_tags.py +216 -0
  237. wxcli/commands/people.py +279 -0
  238. wxcli/commands/person_call_settings.py +71 -0
  239. wxcli/commands/pstn.py +280 -0
  240. wxcli/commands/recording_report.py +154 -0
  241. wxcli/commands/report_templates.py +38 -0
  242. wxcli/commands/reports.py +144 -0
  243. wxcli/commands/resource_group_memberships.py +160 -0
  244. wxcli/commands/resource_groups.py +67 -0
  245. wxcli/commands/roles.py +63 -0
  246. wxcli/commands/room_tabs.py +160 -0
  247. wxcli/commands/rooms.py +225 -0
  248. wxcli/commands/scim_bulk.py +46 -0
  249. wxcli/commands/scim_groups.py +246 -0
  250. wxcli/commands/scim_schemas.py +82 -0
  251. wxcli/commands/scim_users.py +283 -0
  252. wxcli/commands/security_audit.py +54 -0
  253. wxcli/commands/service_apps.py +51 -0
  254. wxcli/commands/single_number_reach.py +209 -0
  255. wxcli/commands/team_memberships.py +155 -0
  256. wxcli/commands/teams.py +153 -0
  257. wxcli/commands/ucm_profile.py +42 -0
  258. wxcli/commands/update.py +219 -0
  259. wxcli/commands/user_settings.py +5116 -0
  260. wxcli/commands/video_mesh.py +1090 -0
  261. wxcli/commands/virtual_extensions.py +502 -0
  262. wxcli/commands/virtual_line_settings.py +2072 -0
  263. wxcli/commands/webhooks.py +176 -0
  264. wxcli/commands/wholesale_billing_reports.py +147 -0
  265. wxcli/commands/wholesale_provisioning.py +523 -0
  266. wxcli/commands/workspace_locations.py +339 -0
  267. wxcli/commands/workspace_metrics.py +103 -0
  268. wxcli/commands/workspace_personalization.py +70 -0
  269. wxcli/commands/workspace_settings.py +3347 -0
  270. wxcli/commands/workspaces.py +279 -0
  271. wxcli/commands/xapi.py +114 -0
  272. wxcli/config.py +139 -0
  273. wxcli/errors.py +77 -0
  274. wxcli/main.py +210 -0
  275. wxcli/migration/CLAUDE.md +106 -0
  276. wxcli/migration/__init__.py +1 -0
  277. wxcli/migration/advisory/CLAUDE.md +196 -0
  278. wxcli/migration/advisory/__init__.py +46 -0
  279. wxcli/migration/advisory/advisor.py +107 -0
  280. wxcli/migration/advisory/advisory_patterns.py +2552 -0
  281. wxcli/migration/advisory/recommendation_rules.py +835 -0
  282. wxcli/migration/cucm/CLAUDE.md +74 -0
  283. wxcli/migration/cucm/__init__.py +5 -0
  284. wxcli/migration/cucm/connection.py +265 -0
  285. wxcli/migration/cucm/discovery.py +225 -0
  286. wxcli/migration/cucm/extractors/__init__.py +1 -0
  287. wxcli/migration/cucm/extractors/announcements.py +92 -0
  288. wxcli/migration/cucm/extractors/base.py +90 -0
  289. wxcli/migration/cucm/extractors/device_profiles.py +98 -0
  290. wxcli/migration/cucm/extractors/devices.py +193 -0
  291. wxcli/migration/cucm/extractors/e911.py +103 -0
  292. wxcli/migration/cucm/extractors/features.py +309 -0
  293. wxcli/migration/cucm/extractors/helpers.py +73 -0
  294. wxcli/migration/cucm/extractors/informational.py +295 -0
  295. wxcli/migration/cucm/extractors/locations.py +221 -0
  296. wxcli/migration/cucm/extractors/moh.py +100 -0
  297. wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
  298. wxcli/migration/cucm/extractors/routing.py +493 -0
  299. wxcli/migration/cucm/extractors/shared_lines.py +146 -0
  300. wxcli/migration/cucm/extractors/templates.py +229 -0
  301. wxcli/migration/cucm/extractors/tier4.py +173 -0
  302. wxcli/migration/cucm/extractors/users.py +240 -0
  303. wxcli/migration/cucm/extractors/voicemail.py +243 -0
  304. wxcli/migration/cucm/extractors/workspaces.py +88 -0
  305. wxcli/migration/cucm/unity_connection.py +304 -0
  306. wxcli/migration/execute/CLAUDE.md +372 -0
  307. wxcli/migration/execute/__init__.py +303 -0
  308. wxcli/migration/execute/batch.py +277 -0
  309. wxcli/migration/execute/dependency.py +483 -0
  310. wxcli/migration/execute/engine.py +964 -0
  311. wxcli/migration/execute/handlers.py +2232 -0
  312. wxcli/migration/execute/planner.py +1939 -0
  313. wxcli/migration/execute/runtime.py +571 -0
  314. wxcli/migration/export/CLAUDE.md +49 -0
  315. wxcli/migration/export/__init__.py +8 -0
  316. wxcli/migration/export/csv_export.py +126 -0
  317. wxcli/migration/export/deployment_plan.py +479 -0
  318. wxcli/migration/export/json_export.py +60 -0
  319. wxcli/migration/models.py +941 -0
  320. wxcli/migration/phone_models.py +50 -0
  321. wxcli/migration/preflight/CLAUDE.md +52 -0
  322. wxcli/migration/preflight/__init__.py +89 -0
  323. wxcli/migration/preflight/checks.py +911 -0
  324. wxcli/migration/preflight/runner.py +293 -0
  325. wxcli/migration/rate_limiter.py +144 -0
  326. wxcli/migration/report/CLAUDE.md +245 -0
  327. wxcli/migration/report/__init__.py +7 -0
  328. wxcli/migration/report/appendix.py +2437 -0
  329. wxcli/migration/report/assembler.py +183 -0
  330. wxcli/migration/report/charts.py +263 -0
  331. wxcli/migration/report/executive.py +776 -0
  332. wxcli/migration/report/explainer.py +704 -0
  333. wxcli/migration/report/helpers.py +74 -0
  334. wxcli/migration/report/ingest.py +152 -0
  335. wxcli/migration/report/notice_templates.py +192 -0
  336. wxcli/migration/report/score.py +375 -0
  337. wxcli/migration/report/styles.py +1052 -0
  338. wxcli/migration/report/user_diff.py +1052 -0
  339. wxcli/migration/report/user_notice.py +425 -0
  340. wxcli/migration/state.py +139 -0
  341. wxcli/migration/store.py +860 -0
  342. wxcli/migration/transform/CLAUDE.md +107 -0
  343. wxcli/migration/transform/__init__.py +12 -0
  344. wxcli/migration/transform/analysis_pipeline.py +453 -0
  345. wxcli/migration/transform/analyzers/__init__.py +142 -0
  346. wxcli/migration/transform/analyzers/css_permission.py +189 -0
  347. wxcli/migration/transform/analyzers/css_routing.py +335 -0
  348. wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
  349. wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
  350. wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
  351. wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
  352. wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
  353. wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
  354. wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
  355. wxcli/migration/transform/analyzers/missing_data.py +300 -0
  356. wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
  357. wxcli/migration/transform/analyzers/shared_line.py +170 -0
  358. wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
  359. wxcli/migration/transform/analyzers/workspace_license.py +212 -0
  360. wxcli/migration/transform/cross_reference.py +1136 -0
  361. wxcli/migration/transform/cucm_pattern.py +246 -0
  362. wxcli/migration/transform/decisions.py +301 -0
  363. wxcli/migration/transform/e164.py +145 -0
  364. wxcli/migration/transform/engine.py +256 -0
  365. wxcli/migration/transform/mappers/CLAUDE.md +123 -0
  366. wxcli/migration/transform/mappers/__init__.py +76 -0
  367. wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
  368. wxcli/migration/transform/mappers/base.py +190 -0
  369. wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
  370. wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
  371. wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
  372. wxcli/migration/transform/mappers/css_mapper.py +868 -0
  373. wxcli/migration/transform/mappers/dect_mapper.py +367 -0
  374. wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
  375. wxcli/migration/transform/mappers/device_mapper.py +227 -0
  376. wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
  377. wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
  378. wxcli/migration/transform/mappers/e911_mapper.py +129 -0
  379. wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
  380. wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
  381. wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
  382. wxcli/migration/transform/mappers/line_mapper.py +310 -0
  383. wxcli/migration/transform/mappers/location_mapper.py +235 -0
  384. wxcli/migration/transform/mappers/moh_mapper.py +114 -0
  385. wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
  386. wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
  387. wxcli/migration/transform/mappers/routing_mapper.py +821 -0
  388. wxcli/migration/transform/mappers/snr_mapper.py +201 -0
  389. wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
  390. wxcli/migration/transform/mappers/user_mapper.py +264 -0
  391. wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
  392. wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
  393. wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
  394. wxcli/migration/transform/normalizers.py +2008 -0
  395. wxcli/migration/transform/pattern_converter.py +106 -0
  396. wxcli/migration/transform/pipeline.py +271 -0
  397. wxcli/migration/transform/rules.py +255 -0
  398. wxcli/org_health/CLAUDE.md +63 -0
  399. wxcli/org_health/__init__.py +7 -0
  400. wxcli/org_health/analyze.py +93 -0
  401. wxcli/org_health/checks.py +458 -0
  402. wxcli/org_health/collector.py +62 -0
  403. wxcli/org_health/models.py +78 -0
  404. wxcli/org_health/report.py +300 -0
  405. wxcli/output.py +101 -0
  406. wxcli-1.2.0.dist-info/METADATA +505 -0
  407. wxcli-1.2.0.dist-info/RECORD +413 -0
  408. wxcli-1.2.0.dist-info/WHEEL +5 -0
  409. wxcli-1.2.0.dist-info/entry_points.txt +2 -0
  410. wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
  411. wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
  412. wxcli-1.2.0.dist-info/scm_version.json +8 -0
  413. wxcli-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,1205 @@
1
+ <!-- Updated by playbook session 2026-03-18 -->
2
+ # Call Control API Reference
3
+
4
+ Webex Calling Call Control APIs enable 3rd-party applications to manage calls on behalf of users. These are **3rd Party Call Control** APIs only, applicable to **Webex Calling Multi-Tenant users** (not UCM or Dedicated Instance users).
5
+
6
+ > **Base path:** `POST /v1/telephony/calls/{action}`
7
+ > **GET endpoints:** `GET /v1/telephony/calls` and `GET /v1/telephony/calls/{callId}`
8
+
9
+ ## Sources
10
+
11
+ - wxc_sdk v1.30.0
12
+ - OpenAPI spec: specs/webex-cloud-calling.json
13
+ - developer.webex.com Call Control APIs
14
+
15
+ ## Table of Contents
16
+
17
+ 1. [Required Scopes](#required-scopes)
18
+ 2. [Raw HTTP Reference](#raw-http-reference-all-call-control-endpoints)
19
+ 3. [CLI Examples](#cli-examples)
20
+ 4. [Call Connection](#1-call-connection)
21
+ 5. [Mid-Call Actions](#2-mid-call-actions)
22
+ 6. [Call Details & History](#3-call-details--history)
23
+ 7. [Data Models](#4-data-models)
24
+ 8. [Service App / Admin API](#5-service-app--admin-api-call-controls-members)
25
+ 9. [Additional API: External Voicemail MWI](#6-additional-api-external-voicemail-mwi)
26
+ 10. [Common Use Cases](#7-common-use-cases)
27
+ 11. [Key Gotchas](#8-key-gotchas)
28
+ 12. [See Also](#see-also)
29
+
30
+ ---
31
+
32
+ ## Required Scopes
33
+
34
+ | Scope | Grants | Used By |
35
+ |-------|--------|---------|
36
+ | `spark:calls_read` | List calls, get call details, call history | User tokens (personal) |
37
+ | `spark:calls_write` | All call control actions (dial, answer, hold, transfer, etc.) | User tokens (personal) |
38
+ | `spark-admin:calls_read` | List calls, get call details for any member | Service App tokens (admin) |
39
+ | `spark-admin:calls_write` | All call control actions for any member | Service App tokens (admin) |
40
+
41
+ - **User-level APIs** (`CallsApi`) use `spark:calls_read` / `spark:calls_write` and operate on the authenticated user's calls.
42
+ - **Service App / Admin APIs** (`CallControlsMembersApi`) use `spark-admin:calls_read` / `spark-admin:calls_write` and operate on any person, workspace, or virtual line by `member_id`.
43
+
44
+ ---
45
+
46
+ ## Raw HTTP Reference (All Call Control Endpoints)
47
+
48
+ All call control endpoints use `https://webexapis.com/v1/telephony/calls/{action}`. Most are POST actions that take a JSON body. GET endpoints retrieve call state.
49
+
50
+ ```python
51
+ from wxc_sdk import WebexSimpleApi
52
+ api = WebexSimpleApi()
53
+ BASE = "https://webexapis.com/v1"
54
+ ```
55
+
56
+ ### User-Level Call Actions
57
+
58
+ | Action | Method | URL | Body Fields |
59
+ |--------|--------|-----|-------------|
60
+ | Dial | POST | `{BASE}/telephony/calls/dial` | `destination` (required), `endpointId`, `lineOwnerId` |
61
+ | Answer | POST | `{BASE}/telephony/calls/answer` | `callId` (required), `endpointId`, `lineOwnerId` |
62
+ | Reject | POST | `{BASE}/telephony/calls/reject` | `callId` (required), `action`, `lineOwnerId` |
63
+ | Hangup | POST | `{BASE}/telephony/calls/hangup` | `callId` (required), `lineOwnerId` |
64
+ | Hold | POST | `{BASE}/telephony/calls/hold` | `callId` (required), `lineOwnerId` |
65
+ | Resume | POST | `{BASE}/telephony/calls/resume` | `callId` (required), `lineOwnerId` |
66
+ | Mute | POST | `{BASE}/telephony/calls/mute` | `callId` (required), `lineOwnerId` |
67
+ | Unmute | POST | `{BASE}/telephony/calls/unmute` | `callId` (required), `lineOwnerId` |
68
+ | Divert | POST | `{BASE}/telephony/calls/divert` | `callId` (required), `destination`, `toVoicemail`, `lineOwnerId` |
69
+ | Transfer | POST | `{BASE}/telephony/calls/transfer` | `callId1`, `callId2`, `destination`, `lineOwnerId` |
70
+ | Park | POST | `{BASE}/telephony/calls/park` | `callId` (required), `destination`, `isGroupPark`, `lineOwnerId` |
71
+ | Retrieve | POST | `{BASE}/telephony/calls/retrieve` | `destination`, `endpointId`, `lineOwnerId` |
72
+ | Pull | POST | `{BASE}/telephony/calls/pull` | `endpointId`, `lineOwnerId` |
73
+ | Push | POST | `{BASE}/telephony/calls/push` | `callId`, `lineOwnerId` |
74
+ | Pickup | POST | `{BASE}/telephony/calls/pickup` | `target`, `endpointId`, `lineOwnerId` |
75
+ | Barge In | POST | `{BASE}/telephony/calls/bargeIn` | `target` (required), `endpointId`, `lineOwnerId` |
76
+ | Conference | POST | `{BASE}/telephony/calls/conference` | `callId1`, `callId2`, `lineOwnerId` |
77
+ | Start Recording | POST | `{BASE}/telephony/calls/startRecording` | `callId` (required), `lineOwnerId` |
78
+ | Stop Recording | POST | `{BASE}/telephony/calls/stopRecording` | `callId` (required), `lineOwnerId` |
79
+ | Pause Recording | POST | `{BASE}/telephony/calls/pauseRecording` | `callId` (required), `lineOwnerId` |
80
+ | Resume Recording | POST | `{BASE}/telephony/calls/resumeRecording` | `callId` (required), `lineOwnerId` |
81
+ | Transmit DTMF | POST | `{BASE}/telephony/calls/transmitDtmf` | `callId` (required), `dtmf` (required), `lineOwnerId` |
82
+
83
+ ### User-Level Read Endpoints
84
+
85
+ | Action | Method | URL | Query Params | Response Key |
86
+ |--------|--------|-----|-------------|--------------|
87
+ | List Calls | GET | `{BASE}/telephony/calls` | `lineOwnerId` | `calls` |
88
+ | Get Call Details | GET | `{BASE}/telephony/calls/{callId}` | `lineOwnerId` | (direct object) |
89
+ | List Call History | GET | `{BASE}/telephony/calls/history` | `type` | `history` |
90
+
91
+ ### Service App / Members Endpoints
92
+
93
+ | Action | Method | URL | Body Fields |
94
+ |--------|--------|-----|-------------|
95
+ | Dial by Member | POST | `{BASE}/telephony/calls/members/{memberId}/dial` | `destination`, `endpointId` |
96
+ | Answer by Member | POST | `{BASE}/telephony/calls/members/{memberId}/answer` | `callId`, `endpointId` |
97
+ | Hangup by Member | POST | `{BASE}/telephony/calls/members/{memberId}/hangup` | `callId` |
98
+ | List Calls by Member | GET | `{BASE}/telephony/calls/members/{memberId}/calls` | (none) |
99
+ | Get Call Details by Member | GET | `{BASE}/telephony/calls/members/{memberId}/calls/{callId}` | (none) |
100
+
101
+ ### Raw HTTP Examples
102
+
103
+ #### Dial a call
104
+
105
+ ```python
106
+ body = {"destination": "+12223334444", "endpointId": "Y2lzY29zcGFyay..."}
107
+ result = api.session.rest_post(f"{BASE}/telephony/calls/dial", json=body)
108
+ # Returns: {callId, callSessionId}
109
+ ```
110
+
111
+ #### List active calls
112
+
113
+ ```python
114
+ result = api.session.rest_get(f"{BASE}/telephony/calls")
115
+ calls = result.get("calls", [])
116
+ # Each call: {id, callSessionId, personality, state, remoteParty: {name, number, ...}, created, answered, ...}
117
+ ```
118
+
119
+ #### Get call details
120
+
121
+ ```python
122
+ result = api.session.rest_get(f"{BASE}/telephony/calls/{call_id}")
123
+ # Returns full call object with state, remoteParty, timestamps, etc.
124
+ ```
125
+
126
+ #### List call history
127
+
128
+ ```python
129
+ result = api.session.rest_get(f"{BASE}/telephony/calls/history", params={"type": "placed"})
130
+ history = result.get("history", [])
131
+ # Each record: {type, name, number, privacyEnabled, time}
132
+ ```
133
+
134
+ #### Hold, then transfer
135
+
136
+ ```python
137
+ # Put caller on hold
138
+ api.session.rest_post(f"{BASE}/telephony/calls/hold", json={"callId": caller_call_id})
139
+
140
+ # Dial consult target
141
+ consult = api.session.rest_post(f"{BASE}/telephony/calls/dial", json={"destination": "+15551234567"})
142
+
143
+ # Transfer both calls together
144
+ api.session.rest_post(f"{BASE}/telephony/calls/transfer", json={
145
+ "callId1": caller_call_id,
146
+ "callId2": consult["callId"]
147
+ })
148
+ ```
149
+
150
+ #### Park and retrieve
151
+
152
+ ```python
153
+ # Park
154
+ parked = api.session.rest_post(f"{BASE}/telephony/calls/park", json={"callId": call_id})
155
+ park_number = parked.get("parkedAgainst", {}).get("number")
156
+
157
+ # Retrieve (from any device)
158
+ retrieved = api.session.rest_post(f"{BASE}/telephony/calls/retrieve", json={"destination": park_number})
159
+ ```
160
+
161
+ #### Service App: Dial on behalf of a member
162
+
163
+ ```python
164
+ body = {"destination": "+12223334444"}
165
+ result = api.session.rest_post(f"{BASE}/telephony/calls/members/{member_id}/dial", json=body)
166
+ # Returns: {callId, callSessionId}
167
+ ```
168
+
169
+ #### External Voicemail MWI
170
+
171
+ ```python
172
+ body = {"action": "SET"} # or "CLEAR"
173
+ api.session.rest_post(f"{BASE}/telephony/externalVoicemail/mwi", json=body, params={
174
+ "id": user_id,
175
+ "orgId": org_id
176
+ })
177
+ ```
178
+
179
+ ### Raw HTTP Gotchas
180
+
181
+ 1. **All action endpoints are POST** -- even hold, resume, mute, unmute. Only list/details/history are GET.
182
+ 2. **Response varies by action** -- `dial`, `pickup`, `retrieve`, `pull`, `bargeIn` return `{callId, callSessionId}`. Most others return 204 (no content).
183
+ 3. **Transfer response depends on mode** -- auto/consultative returns 204; mute transfer returns 201 with `{callId, callSessionId}`.
184
+ 4. **`id` vs `callId`** -- GET responses return `id` as the call identifier. Webhook events use `callId`. When passing to action endpoints, always use `callId` in the request body.
185
+ 5. **`lineOwnerId`** is optional on all endpoints -- only needed when controlling a secondary line belonging to another user/workspace/virtual line.
186
+ 6. **Members API does not have `lineOwnerId`** -- the member_id in the URL serves the same purpose.
187
+ 7. **No pagination on call list** -- `list_calls` returns all active calls for the user (typically a small number).
188
+ 8. **History max 20 per type** -- `list_call_history` returns at most 20 records per type (placed/missed/received), max 60 total.
189
+
190
+ ---
191
+
192
+ ## CLI Examples
193
+
194
+ > **Important:** Call control commands require a **user-level OAuth token**, not an admin token. Admin tokens return 400 "Target user not authorized". Configure wxcli with a user's personal access token: `wxcli configure`.
195
+
196
+ ### Command Reference
197
+
198
+ All 29 commands in the `call-controls` group:
199
+
200
+ | Command | Description | Key Options |
201
+ |---------|-------------|-------------|
202
+ | `create` | Dial | `--destination` (required), `--endpoint-id`, `--line-owner-id` |
203
+ | `create-answer-calls` | Answer | `--call-id` (required), `--endpoint-id`, `--line-owner-id` |
204
+ | `create-reject` | Reject | `--call-id` (required), `--action`, `--line-owner-id` |
205
+ | `create-hangup-calls` | Hangup | `--call-id` (required), `--line-owner-id` |
206
+ | `create-hold` | Hold | `--call-id` (required), `--line-owner-id` |
207
+ | `create-resume` | Resume | `--call-id` (required), `--line-owner-id` |
208
+ | `create-mute` | Mute | `--call-id` (required), `--line-owner-id` |
209
+ | `create-unmute` | Unmute | `--call-id` (required), `--line-owner-id` |
210
+ | `create-divert` | Divert | `--call-id` (required), `--destination`, `--to-voicemail`, `--line-owner-id` |
211
+ | `create-transfer` | Transfer | `--call-id1`, `--call-id2`, `--destination`, `--line-owner-id` |
212
+ | `create-park` | Park | `--call-id` (required), `--destination`, `--is-group-park`, `--line-owner-id` |
213
+ | `create-retrieve` | Retrieve | `--destination`, `--endpoint-id`, `--line-owner-id` |
214
+ | `create-pull` | Pull | `--endpoint-id`, `--line-owner-id` |
215
+ | `create-push` | Push | `--call-id`, `--line-owner-id` |
216
+ | `create-pickup` | Pickup | `--target`, `--endpoint-id`, `--line-owner-id` |
217
+ | `create-barge-in` | Barge In | `--target` (required), `--endpoint-id`, `--line-owner-id` |
218
+ | `create-start-recording` | Start Recording | `--call-id`, `--line-owner-id` |
219
+ | `create-stop-recording` | Stop Recording | `--call-id`, `--line-owner-id` |
220
+ | `create-pause-recording` | Pause Recording | `--call-id`, `--line-owner-id` |
221
+ | `create-resume-recording` | Resume Recording | `--call-id`, `--line-owner-id` |
222
+ | `create-transmit-dtmf` | Transmit DTMF | `--call-id`, `--dtmf`, `--line-owner-id` |
223
+ | `list` | List Calls | `--line-owner-id`, `-o table\|json` |
224
+ | `show` | Get Call Details | `CALL_ID` (positional, required), `--line-owner-id`, `-o table\|json` |
225
+ | `list-history` | List Call History | `--type placed\|missed\|received`, `-o table\|json` |
226
+ | `create-dial` | Dial by Member ID | `MEMBER_ID` (positional), `--destination` (required), `--endpoint-id` |
227
+ | `create-answer-members` | Answer by Member ID | `MEMBER_ID` (positional), `--call-id` (required), `--endpoint-id` |
228
+ | `create-hangup-members` | Hangup by Member ID | `MEMBER_ID` (positional), `--call-id` (required) |
229
+ | `list-calls` | List Calls by Member ID | `MEMBER_ID` (positional), `-o table\|json` |
230
+ | `show-calls` | Get Call Details by Member ID | `MEMBER_ID` `CALL_ID` (positional), `-o table\|json` |
231
+
232
+ ### Call Connection
233
+
234
+ ```bash
235
+ # Dial a number (rings all user devices, then places outbound call)
236
+ wxcli call-controls create --destination "+12223334444"
237
+
238
+ # Dial an extension
239
+ wxcli call-controls create --destination "1234"
240
+
241
+ # Dial on a specific device/app
242
+ wxcli call-controls create --destination "+12223334444" --endpoint-id Y2lzY29zcGFyay...
243
+
244
+ # Answer an incoming call
245
+ wxcli call-controls create-answer-calls --call-id Y2lzY29zcGFyay...
246
+
247
+ # Answer on a specific device
248
+ wxcli call-controls create-answer-calls --call-id Y2lzY29zcGFyay... --endpoint-id Y2lzY29zcGFyay...
249
+
250
+ # Reject an incoming call (defaults to busy)
251
+ wxcli call-controls create-reject --call-id Y2lzY29zcGFyay...
252
+
253
+ # Reject with a specific action (busy, temporarilyUnavailable, ignore)
254
+ wxcli call-controls create-reject --call-id Y2lzY29zcGFyay... --action temporarilyUnavailable
255
+
256
+ # Hang up a call
257
+ wxcli call-controls create-hangup-calls --call-id Y2lzY29zcGFyay...
258
+
259
+ # Pick up a call from your call pickup group
260
+ wxcli call-controls create-pickup
261
+
262
+ # Pick up a call from a specific user
263
+ wxcli call-controls create-pickup --target "+12223334444"
264
+
265
+ # Divert a call to another number
266
+ wxcli call-controls create-divert --call-id Y2lzY29zcGFyay... --destination "+15551234567"
267
+
268
+ # Divert a call to voicemail
269
+ wxcli call-controls create-divert --call-id Y2lzY29zcGFyay... --to-voicemail
270
+ ```
271
+
272
+ ### Mid-Call Actions
273
+
274
+ ```bash
275
+ # Hold a call
276
+ wxcli call-controls create-hold --call-id Y2lzY29zcGFyay...
277
+
278
+ # Resume a held call
279
+ wxcli call-controls create-resume --call-id Y2lzY29zcGFyay...
280
+
281
+ # Mute a call
282
+ wxcli call-controls create-mute --call-id Y2lzY29zcGFyay...
283
+
284
+ # Unmute a call
285
+ wxcli call-controls create-unmute --call-id Y2lzY29zcGFyay...
286
+ ```
287
+
288
+ ### Transfer
289
+
290
+ ```bash
291
+ # Auto transfer (user has exactly 2 calls -- they are merged automatically)
292
+ wxcli call-controls create-transfer
293
+
294
+ # Consultative/attended transfer (specify both call IDs)
295
+ wxcli call-controls create-transfer --call-id1 Y2lzY29zcGFyay_call1... --call-id2 Y2lzY29zcGFyay_call2...
296
+
297
+ # Mute transfer (transfer to a new destination; waits for answer)
298
+ wxcli call-controls create-transfer --call-id1 Y2lzY29zcGFyay... --destination "+15551234567"
299
+ ```
300
+
301
+ ### Park / Retrieve
302
+
303
+ ```bash
304
+ # Park a call (parks against self; returns the park extension number)
305
+ wxcli call-controls create-park --call-id Y2lzY29zcGFyay...
306
+
307
+ # Park a call at a specific extension
308
+ wxcli call-controls create-park --call-id Y2lzY29zcGFyay... --destination "7001"
309
+
310
+ # Park using the call park group (auto-selects an available slot)
311
+ wxcli call-controls create-park --call-id Y2lzY29zcGFyay... --is-group-park
312
+
313
+ # Retrieve a parked call (use the park number from the park response)
314
+ wxcli call-controls create-retrieve --destination "7001"
315
+ ```
316
+
317
+ ### Recording Control
318
+
319
+ ```bash
320
+ # Start recording (user must have "On Demand" recording mode)
321
+ wxcli call-controls create-start-recording --call-id Y2lzY29zcGFyay...
322
+
323
+ # Pause recording (e.g., for sensitive info like credit card numbers)
324
+ wxcli call-controls create-pause-recording --call-id Y2lzY29zcGFyay...
325
+
326
+ # Resume recording
327
+ wxcli call-controls create-resume-recording --call-id Y2lzY29zcGFyay...
328
+
329
+ # Stop recording
330
+ wxcli call-controls create-stop-recording --call-id Y2lzY29zcGFyay...
331
+ ```
332
+
333
+ ### Other Actions
334
+
335
+ ```bash
336
+ # Transmit DTMF tones (comma = pause between digits)
337
+ wxcli call-controls create-transmit-dtmf --call-id Y2lzY29zcGFyay... --dtmf "1,234"
338
+
339
+ # Pull a call to a different device (move call between desk phone, mobile, desktop)
340
+ wxcli call-controls create-pull --endpoint-id Y2lzY29zcGFyay...
341
+
342
+ # Push a call to the executive (executive-assistant feature only)
343
+ wxcli call-controls create-push --call-id Y2lzY29zcGFyay...
344
+
345
+ # Barge in on another user's active call
346
+ wxcli call-controls create-barge-in --target "+12223334444"
347
+ ```
348
+
349
+ ### Call Details & History
350
+
351
+ ```bash
352
+ # List all active calls
353
+ wxcli call-controls list
354
+ wxcli call-controls list -o json
355
+
356
+ # Get details for a specific active call
357
+ wxcli call-controls show Y2lzY29zcGFyay...
358
+ wxcli call-controls show Y2lzY29zcGFyay... -o table
359
+
360
+ # List call history (all types -- placed, missed, received; max 20 each)
361
+ wxcli call-controls list-history
362
+
363
+ # List only missed calls
364
+ wxcli call-controls list-history --type missed
365
+
366
+ # List only placed calls as JSON
367
+ wxcli call-controls list-history --type placed -o json
368
+ ```
369
+
370
+ ### Service App / Members API
371
+
372
+ > These commands use `spark-admin:calls_read` / `spark-admin:calls_write` scopes and operate on behalf of a person, workspace, or virtual line by member ID.
373
+
374
+ ```bash
375
+ # Dial on behalf of a user (Service App token required)
376
+ wxcli call-controls create-dial <member_id> --destination "+12223334444"
377
+
378
+ # Answer a call on behalf of a user
379
+ wxcli call-controls create-answer-members <member_id> --call-id Y2lzY29zcGFyay...
380
+
381
+ # Hang up a call on behalf of a user
382
+ wxcli call-controls create-hangup-members <member_id> --call-id Y2lzY29zcGFyay...
383
+
384
+ # List active calls for a user
385
+ wxcli call-controls list-calls <member_id>
386
+
387
+ # Get call details for a specific call on a user
388
+ wxcli call-controls show-calls <member_id> Y2lzY29zcGFyay...
389
+ ```
390
+
391
+ ### Hold, Consult, Transfer Pattern (CLI Workflow)
392
+
393
+ A common call center pattern: put the caller on hold, dial a consult target, then transfer both calls together.
394
+
395
+ ```bash
396
+ # Step 1: Put the current call on hold
397
+ wxcli call-controls create-hold --call-id <caller_call_id>
398
+
399
+ # Step 2: Dial the transfer target
400
+ wxcli call-controls create --destination "+15551234567"
401
+ # Note the new call_id from the response
402
+
403
+ # Step 3: After speaking with the transfer target, transfer both calls
404
+ wxcli call-controls create-transfer --call-id1 <caller_call_id> --call-id2 <consult_call_id>
405
+ ```
406
+
407
+ ---
408
+
409
+ ## 1. Call Connection
410
+
411
+ ### Dial (Click-to-Call)
412
+
413
+ Initiate an outbound call. Alerts all user devices (or a specific endpoint). When the user answers on one device, the outbound call is placed from that device to the destination.
414
+
415
+ ```
416
+ POST /v1/telephony/calls/dial
417
+ ```
418
+
419
+ **SDK Signature:**
420
+ ```python
421
+ CallsApi.dial(
422
+ destination: str, # digits, URI, SIP address, tel: URI
423
+ endpoint_id: str = None, # specific device/app to alert
424
+ line_owner_id: str = None # secondary line owner (user/workspace/virtual line)
425
+ ) -> CallInfo
426
+ ```
427
+
428
+ **Request body:**
429
+ ```json
430
+ {
431
+ "destination": "+12223334444",
432
+ "endpointId": "Y2lzY29zcGFyay..."
433
+ }
434
+ ```
435
+
436
+ **Response (201):**
437
+ ```json
438
+ {
439
+ "callId": "Y2lzY29zcGFyay...",
440
+ "callSessionId": "OGQ3YzhkNzgt..."
441
+ }
442
+ ```
443
+
444
+ **Destination formats:** `1234`, `2223334444`, `+12223334444`, `*73`, `tel:+12223334444`, `user@company.domain`, `sip:user@company.domain`
445
+
446
+ ---
447
+
448
+ ### Answer
449
+
450
+ Answer an incoming call on a specific device (or the user's primary device if no endpoint specified).
451
+
452
+ ```
453
+ POST /v1/telephony/calls/answer
454
+ ```
455
+
456
+ **SDK Signature:**
457
+ ```python
458
+ CallsApi.answer(
459
+ call_id: str,
460
+ endpoint_id: str = None,
461
+ line_owner_id: str = None
462
+ ) -> None
463
+ ```
464
+
465
+ **Request body:**
466
+ ```json
467
+ {
468
+ "callId": "Y2lzY29zcGFyay...",
469
+ "endpointId": "Y2lzY29zcGFyay..."
470
+ }
471
+ ```
472
+
473
+ **Notes:**
474
+ - Rejected if the device is not alerting for the call.
475
+ - Rejected if the device does not support answer via API.
476
+
477
+ ---
478
+
479
+ ### Pickup
480
+
481
+ Pick up an incoming call ringing on another user's device. Initiates a new call (similar to dial) to perform the pickup.
482
+
483
+ ```
484
+ POST /v1/telephony/calls/pickup
485
+ ```
486
+
487
+ **SDK Signature:**
488
+ ```python
489
+ CallsApi.pickup(
490
+ target: str = None, # user to pick up from; omit for call pickup group
491
+ endpoint_id: str = None,
492
+ line_owner_id: str = None
493
+ ) -> CallInfo
494
+ ```
495
+
496
+ - **No target:** picks up from the user's call pickup group.
497
+ - **With target:** picks up from the specified user (digits or URI).
498
+
499
+ **Response:** Returns `CallInfo` (callId + callSessionId).
500
+
501
+ ---
502
+
503
+ ### Reject
504
+
505
+ Reject an unanswered incoming call.
506
+
507
+ ```
508
+ POST /v1/telephony/calls/reject
509
+ ```
510
+
511
+ **SDK Signature:**
512
+ ```python
513
+ CallsApi.reject(
514
+ call_id: str,
515
+ action: RejectAction = None, # defaults to 'busy' if omitted
516
+ line_owner_id: str = None
517
+ ) -> None
518
+ ```
519
+
520
+ **RejectAction values:**
521
+
522
+ | Value | Behavior |
523
+ |-------|----------|
524
+ | `busy` | Send the call to busy (default) |
525
+ | `temporarilyUnavailable` | Send the call to temporarily unavailable |
526
+ | `ignore` | Continue ringback to caller, stop alerting user's devices |
527
+
528
+ ---
529
+
530
+ ### Divert (Blind Transfer)
531
+
532
+ Divert a call to another destination or to voicemail.
533
+
534
+ ```
535
+ POST /v1/telephony/calls/divert
536
+ ```
537
+
538
+ **SDK Signature:**
539
+ ```python
540
+ CallsApi.divert(
541
+ call_id: str,
542
+ destination: str = None, # required if toVoicemail is false
543
+ to_voicemail: bool = None, # True = send to voicemail
544
+ line_owner_id: str = None
545
+ ) -> None
546
+ ```
547
+
548
+ **Request body examples:**
549
+
550
+ Divert to another number:
551
+ ```json
552
+ {
553
+ "callId": "Y2lzY29zcGFyay...",
554
+ "destination": "+12223334444"
555
+ }
556
+ ```
557
+
558
+ Divert to own voicemail:
559
+ ```json
560
+ {
561
+ "callId": "Y2lzY29zcGFyay...",
562
+ "toVoicemail": true
563
+ }
564
+ ```
565
+
566
+ Divert to another user's voicemail:
567
+ ```json
568
+ {
569
+ "callId": "Y2lzY29zcGFyay...",
570
+ "destination": "+12223334444",
571
+ "toVoicemail": true
572
+ }
573
+ ```
574
+
575
+ ### Gotchas
576
+
577
+ - **Answer rejection:** Answer is rejected if the device is not alerting for the call, or if the device does not support answer via API.
578
+
579
+ ---
580
+
581
+ ## 2. Mid-Call Actions
582
+
583
+ ### Hold
584
+
585
+ Place a connected call on hold.
586
+
587
+ ```
588
+ POST /v1/telephony/calls/hold
589
+ ```
590
+
591
+ **SDK Signature:**
592
+ ```python
593
+ CallsApi.hold(call_id: str, line_owner_id: str = None) -> None
594
+ ```
595
+
596
+ ---
597
+
598
+ ### Resume
599
+
600
+ Resume a held call.
601
+
602
+ ```
603
+ POST /v1/telephony/calls/resume
604
+ ```
605
+
606
+ **SDK Signature:**
607
+ ```python
608
+ CallsApi.resume(call_id: str, line_owner_id: str = None) -> None
609
+ ```
610
+
611
+ ---
612
+
613
+ ### Transfer
614
+
615
+ Transfer two calls together. Supports multiple transfer modes depending on parameters.
616
+
617
+ ```
618
+ POST /v1/telephony/calls/transfer
619
+ ```
620
+
621
+ **SDK Signature:**
622
+ ```python
623
+ CallsApi.transfer(
624
+ call_id1: str = None,
625
+ call_id2: str = None,
626
+ destination: str = None,
627
+ line_owner_id: str = None
628
+ ) -> CallInfo
629
+ ```
630
+
631
+ **Transfer modes:**
632
+
633
+ | Mode | Parameters | Response | Description |
634
+ |------|-----------|----------|-------------|
635
+ | **Auto (2 calls)** | Neither callId1/callId2 | 204 | User has exactly 2 calls; they are automatically selected and transferred |
636
+ | **Consultative / Attended** | `callId1` + `callId2` | 204 | Transfer two specific calls together (supervised transfer) |
637
+ | **Mute Transfer** | `callId1` + `destination` | 201 | Transfer call to new destination; waits for destination to answer before completing. If destination doesn't answer, call is not transferred |
638
+
639
+ **Note:** Unanswered incoming calls cannot be transferred. Use `divert` instead.
640
+
641
+ ---
642
+
643
+ ### Park
644
+
645
+ Park a connected call. Returns the extension/number to use for retrieval.
646
+
647
+ ```
648
+ POST /v1/telephony/calls/park
649
+ ```
650
+
651
+ **SDK Signature:**
652
+ ```python
653
+ CallsApi.park(
654
+ call_id: str,
655
+ destination: str = None, # where to park; omit to park against self
656
+ is_group_park: bool = None, # True = auto-select from call park group
657
+ line_owner_id: str = None
658
+ ) -> TelephonyParty # parkedAgainst details including number
659
+ ```
660
+
661
+ **Response:** Returns a `TelephonyParty` object (the `parkedAgainst` party). The `number` field from this response is used as the destination for the `retrieve` command.
662
+
663
+ ---
664
+
665
+ ### Retrieve (Unpark)
666
+
667
+ Retrieve a parked call. Initiates a new call (similar to dial) to perform the retrieval.
668
+
669
+ ```
670
+ POST /v1/telephony/calls/retrieve
671
+ ```
672
+
673
+ **SDK Signature:**
674
+ ```python
675
+ CallsApi.retrieve(
676
+ destination: str = None, # where the call is parked; omit if parked against self
677
+ endpoint_id: str = None,
678
+ line_owner_id: str = None
679
+ ) -> CallInfo
680
+ ```
681
+
682
+ ---
683
+
684
+ ### Pull
685
+
686
+ Pull a call from one device to another. Useful for moving a call between desk phone, mobile app, and desktop app.
687
+
688
+ ```
689
+ POST /v1/telephony/calls/pull
690
+ ```
691
+
692
+ **SDK Signature:**
693
+ ```python
694
+ CallsApi.pull(
695
+ endpoint_id: str = None,
696
+ line_owner_id: str = None
697
+ ) -> CallInfo
698
+ ```
699
+
700
+ A temporary new call is initiated. When the user answers on the target device, that device connects to the pulled call and the temporary call is released.
701
+
702
+ ---
703
+
704
+ ### Push (Executive Assistant)
705
+
706
+ Push a call from an assistant to the associated executive.
707
+
708
+ ```
709
+ POST /v1/telephony/calls/push
710
+ ```
711
+
712
+ **SDK Signature:**
713
+ ```python
714
+ CallsApi.push(
715
+ call_id: str = None,
716
+ line_owner_id: str = None
717
+ ) -> None
718
+ ```
719
+
720
+ **Note:** Only valid when the assistant's call is associated with an executive.
721
+
722
+ ---
723
+
724
+ ### Barge In
725
+
726
+ Barge into another user's answered call. Initiates a new call (similar to dial).
727
+
728
+ ```
729
+ POST /v1/telephony/calls/bargeIn
730
+ ```
731
+
732
+ **SDK Signature:**
733
+ ```python
734
+ CallsApi.barge_in(
735
+ target: str, # user to barge in on (digits or URI)
736
+ endpoint_id: str = None,
737
+ line_owner_id: str = None
738
+ ) -> CallInfo
739
+ ```
740
+
741
+ ---
742
+
743
+ ### Conference (3-Way Merge)
744
+
745
+ Merge two active calls into a three-way conference call. The user must have two calls (one active, one held) to merge.
746
+
747
+ ```
748
+ POST /v1/telephony/calls/conference
749
+ ```
750
+
751
+ **SDK Signature:**
752
+ ```python
753
+ CallsApi.conference(
754
+ call_id1: str = None,
755
+ call_id2: str = None,
756
+ line_owner_id: str = None
757
+ ) -> None
758
+ ```
759
+
760
+ If `call_id1` and `call_id2` are omitted, the user must have exactly two calls; they are automatically selected and merged. When specified, both calls are merged into a three-way conference with the user.
761
+
762
+ ---
763
+
764
+ ### Hangup
765
+
766
+ Disconnect a call. If used on an unanswered incoming call, the call is rejected and sent to busy.
767
+
768
+ ```
769
+ POST /v1/telephony/calls/hangup
770
+ ```
771
+
772
+ **SDK Signature:**
773
+ ```python
774
+ CallsApi.hangup(call_id: str, line_owner_id: str = None) -> None
775
+ ```
776
+
777
+ ---
778
+
779
+ ### Mute / Unmute
780
+
781
+ Mute or unmute a call. Only valid on calls that report `muteCapable: true` in call details.
782
+
783
+ ```
784
+ POST /v1/telephony/calls/mute
785
+ POST /v1/telephony/calls/unmute
786
+ ```
787
+
788
+ **SDK Signatures:**
789
+ ```python
790
+ CallsApi.mute(call_id: str, line_owner_id: str = None) -> None
791
+ CallsApi.unmute(call_id: str, line_owner_id: str = None) -> None
792
+ ```
793
+
794
+ ---
795
+
796
+ ### Recording Control
797
+
798
+ Control call recording. Availability depends on the user's call recording mode.
799
+
800
+ | Endpoint | SDK Method | Recording Mode Required |
801
+ |----------|-----------|------------------------|
802
+ | `POST .../startRecording` | `start_recording(call_id, line_owner_id)` | "On Demand" |
803
+ | `POST .../stopRecording` | `stop_recording(call_id, line_owner_id)` | "On Demand" |
804
+ | `POST .../pauseRecording` | `pause_recording(call_id, line_owner_id)` | "On Demand" or "Always with Pause/Resume" |
805
+ | `POST .../resumeRecording` | `resume_recording(call_id, line_owner_id)` | "On Demand" or "Always with Pause/Resume" |
806
+
807
+ **RecordingState values:**
808
+
809
+ | Value | Description |
810
+ |-------|-------------|
811
+ | `pending` | Recording requested but not yet started |
812
+ | `started` | Recording is active |
813
+ | `paused` | Recording is paused |
814
+ | `stopped` | Recording has been stopped |
815
+ | `failed` | Recording failed |
816
+
817
+ ---
818
+
819
+ ### Transmit DTMF
820
+
821
+ Send DTMF tones on an active call.
822
+
823
+ ```
824
+ POST /v1/telephony/calls/transmitDtmf
825
+ ```
826
+
827
+ **SDK Signature:**
828
+ ```python
829
+ CallsApi.transmit_dtmf(
830
+ call_id: str = None,
831
+ dtmf: str = None, # e.g. "1,234" (comma = pause)
832
+ line_owner_id: str = None
833
+ ) -> None
834
+ ```
835
+
836
+ **Valid DTMF characters:** `0-9`, `*`, `#`, `A`, `B`, `C`, `D`
837
+ **Pause:** Use a comma `,` to insert a pause between digits. Example: `"1,234"` sends `1`, pauses, then sends `2`, `3`, `4`.
838
+
839
+ ### Gotchas
840
+
841
+ - **Transfer restrictions:** Unanswered incoming calls cannot be transferred. Use `divert` instead.
842
+ - **Push is executive-assistant only:** `push` is only valid when the assistant's call is associated with an executive.
843
+ - **Mute capability check:** Only calls that report `muteCapable: true` in call details support `mute`/`unmute`. Always check before calling.
844
+ - **DTMF pause character:** Use a comma `,` to insert a pause between DTMF digits. This is not documented prominently in the API reference.
845
+ - **Recording mode dependency:** `start_recording`/`stop_recording` only work when the user's recording mode is "On Demand". `pause_recording`/`resume_recording` work with both "On Demand" and "Always with Pause/Resume".
846
+
847
+ ---
848
+
849
+ ## 3. Call Details & History
850
+
851
+ ### List Active Calls
852
+
853
+ Get all active calls for the user.
854
+
855
+ ```
856
+ GET /v1/telephony/calls
857
+ ```
858
+
859
+ **SDK Signature:**
860
+ ```python
861
+ CallsApi.list_calls(line_owner_id: str = None) -> list[TelephonyCall]
862
+ ```
863
+
864
+ ---
865
+
866
+ ### Get Call Details
867
+
868
+ Get details of a specific active call.
869
+
870
+ ```
871
+ GET /v1/telephony/calls/{callId}
872
+ ```
873
+
874
+ **SDK Signature:**
875
+ ```python
876
+ CallsApi.call_details(
877
+ call_id: str,
878
+ line_owner_id: str = None
879
+ ) -> TelephonyCall
880
+ ```
881
+
882
+ ---
883
+
884
+ ### List Call History
885
+
886
+ Get the user's call history. Returns a maximum of **20 records per type**.
887
+
888
+ ```
889
+ GET /v1/telephony/calls/history
890
+ ```
891
+
892
+ **SDK Signature:**
893
+ ```python
894
+ CallsApi.call_history(history_type: HistoryType = None) -> list[CallHistoryRecord]
895
+ ```
896
+
897
+ **HistoryType values:**
898
+
899
+ | Value | Description |
900
+ |-------|-------------|
901
+ | `placed` | Outgoing calls placed by the user |
902
+ | `missed` | Incoming calls not answered |
903
+ | `received` | Incoming calls answered |
904
+
905
+ If `history_type` is omitted, all types are returned (up to 20 each = max 60 total).
906
+
907
+ **CallHistoryRecord fields:**
908
+
909
+ | Field | Type | Description |
910
+ |-------|------|-------------|
911
+ | `type` | HistoryType | placed, missed, or received |
912
+ | `name` | str (optional) | Party name (if available and privacy not enabled) |
913
+ | `number` | str (optional) | Party number (digits or URI) |
914
+ | `privacy_enabled` | bool | Whether privacy is enabled |
915
+ | `time` | datetime | When the record was created (placed=call time, missed=disconnect time, received=answer time) |
916
+
917
+ ### Gotchas
918
+
919
+ - **Call history limit:** `call_history` returns a maximum of 20 records per type (placed/missed/received). If `history_type` is omitted, all types are returned (up to 20 each = max 60 total).
920
+ - **No pagination on call list:** `list_calls` returns all active calls for the user (typically a small number). There is no pagination support.
921
+
922
+ ---
923
+
924
+ ## 4. Data Models
925
+
926
+ ### TelephonyCall (Call Object)
927
+
928
+ The primary call object returned by list/details endpoints and included in webhook event data.
929
+
930
+ | Field | Type | Description |
931
+ |-------|------|-------------|
932
+ | `call_id` | str | Unique call identifier (aliased from `id` in API responses, `callId` in events) |
933
+ | `call_session_id` | str | Session ID to correlate multiple calls in the same session |
934
+ | `personality` | Personality | Whether user is originator, terminator, or clickToDial |
935
+ | `state` | CallState | Current call state |
936
+ | `remote_party` | TelephonyParty | Details of the other party |
937
+ | `appearance` | int (optional) | Appearance value for ordering calls consistent with device display |
938
+ | `created` | datetime | When the call was created |
939
+ | `answered` | datetime (optional) | When the call was answered |
940
+ | `redirections` | list[Redirection] | Previous redirections (most recent first), only present when state is alerting |
941
+ | `recall` | Recall (optional) | Recall details (e.g., park recall) |
942
+ | `recording_state` | RecordingState (optional) | Current recording state, only present if recording was invoked |
943
+ | `disconnected` | datetime (optional) | When the call was disconnected |
944
+ | `mute_capable` | bool (optional) | Whether the call supports mute/unmute API |
945
+ | `muted` | bool (optional) | Whether the call is currently muted |
946
+
947
+ ### CallInfo (Dial/Pickup/Retrieve Response)
948
+
949
+ Returned by actions that initiate a new call.
950
+
951
+ | Field | Type | Description |
952
+ |-------|------|-------------|
953
+ | `call_id` | str | Unique call identifier |
954
+ | `call_session_id` | str | Session ID for correlating related calls |
955
+
956
+ ### Personality
957
+
958
+ | Value | Description |
959
+ |-------|-------------|
960
+ | `originator` | An outgoing call originated by the user |
961
+ | `terminator` | An incoming call received by the user |
962
+ | `clickToDial` | Alerting for a Click-to-Dial action; becomes `originator` when answered |
963
+
964
+ ### CallState
965
+
966
+ | Value | Description |
967
+ |-------|-------------|
968
+ | `connecting` | Remote party is being alerted |
969
+ | `alerting` | User's devices are alerting for incoming or Click-to-Dial call |
970
+ | `connected` | Call is connected |
971
+ | `held` | User has placed the call on hold |
972
+ | `remoteHeld` | Remote party (same org) has placed the call on hold |
973
+ | `disconnected` | Call has been disconnected |
974
+
975
+ ### CallType
976
+
977
+ | Value | Description |
978
+ |-------|-------------|
979
+ | `location` | Party is within the same location |
980
+ | `organization` | Party is within the same org but different location |
981
+ | `external` | Party is outside the organization |
982
+ | `emergency` | Emergency call destination |
983
+ | `repair` | Repair call destination |
984
+ | `other` | Does not match any defined type (e.g., feature activation code) |
985
+
986
+ ### TelephonyParty
987
+
988
+ | Field | Type | Description |
989
+ |-------|------|-------------|
990
+ | `name` | str (optional) | Party name (if available and privacy not enabled) |
991
+ | `number` | str | Party number (digits or URI) |
992
+ | `person_id` | str (optional) | Party's person ID |
993
+ | `place_id` | str (optional) | Party's place ID |
994
+ | `privacy_enabled` | bool (optional) | Whether privacy is enabled |
995
+ | `call_type` | CallType (optional) | Call type for the party |
996
+
997
+ ### RedirectReason
998
+
999
+ | Value | Description |
1000
+ |-------|-------------|
1001
+ | `busy` | Forwarded by Call Forwarding Busy |
1002
+ | `noAnswer` | Forwarded by Call Forwarding No Answer |
1003
+ | `unavailable` | Forwarded by Business Continuity |
1004
+ | `unconditional` | Forwarded by Call Forwarding Always |
1005
+ | `timeOfDay` | Forwarded by Selective Call Forwarding (schedule) |
1006
+ | `divert` | Redirected by divert action |
1007
+ | `followMe` | Redirected by Simultaneous Ring |
1008
+ | `huntGroup` | Redirected by Hunt Group routing |
1009
+ | `callQueue` | Redirected by Call Queue routing |
1010
+ | `unknown` | Unknown redirect reason |
1011
+
1012
+ ### RejectAction
1013
+
1014
+ | Value | Behavior |
1015
+ |-------|----------|
1016
+ | `busy` | Send to busy (default) |
1017
+ | `temporarilyUnavailable` | Send to temporarily unavailable |
1018
+ | `ignore` | Continue ringback, stop alerting user devices |
1019
+
1020
+ ### RecordingState
1021
+
1022
+ | Value | Description |
1023
+ |-------|-------------|
1024
+ | `pending` | Requested but not yet started |
1025
+ | `started` | Recording is active |
1026
+ | `paused` | Recording is paused |
1027
+ | `stopped` | Recording has been stopped |
1028
+ | `failed` | Recording failed |
1029
+
1030
+ ---
1031
+
1032
+ ## 5. Service App / Admin API (Call Controls Members)
1033
+
1034
+ For **Service Apps** that need to control calls on behalf of users, workspaces, or virtual lines. Uses `spark-admin:calls_read` and `spark-admin:calls_write` scopes.
1035
+
1036
+ > **Note:** The `spark-admin:calls_read` and `spark-admin:calls_write` scopes listed above for the Members API cannot be confirmed from any publicly indexed developer.webex.com page. They may be accurate but should be verified against the live API reference or Webex TAC before building production integrations against the Members API.
1037
+
1038
+ **Base path:** `POST /v1/telephony/calls/members/{memberId}/{action}`
1039
+
1040
+ The Members API mirrors the user-level API but adds `member_id` and `org_id` parameters.
1041
+
1042
+ ### Available Members Endpoints
1043
+
1044
+ | Action | SDK Method | Returns |
1045
+ |--------|-----------|---------|
1046
+ | List Calls | `CallControlsMembersApi.list_calls(member_id, org_id)` | `list[TelephonyCall]` |
1047
+ | Get Call Details | `CallControlsMembersApi.get_call_details(member_id, call_id, org_id)` | `TelephonyCall` |
1048
+ | Dial | `CallControlsMembersApi.dial(member_id, destination, endpoint_id, org_id)` | `CallInfo` |
1049
+ | Answer | `CallControlsMembersApi.answer(member_id, call_id, endpoint_id, org_id)` | None |
1050
+ | Hangup | `CallControlsMembersApi.hangup(member_id, call_id, org_id)` | None |
1051
+
1052
+ **`member_id`** can be one of: person ID, workspace ID, or virtual line ID.
1053
+
1054
+ ### Gotchas
1055
+
1056
+ - **Members API supports a limited action set.** Only Dial, Answer, Hangup, List Calls, and Get Call Details are available. Hold, Resume, Transfer, Mute, Park, and Barge-in are user-level API operations only and are NOT available on the Members API path. Service App integrations requiring these operations must use user-level OAuth tokens (`spark:calls_write`) acting as the target user.
1057
+
1058
+ ---
1059
+
1060
+ ## 6. Additional API: External Voicemail MWI
1061
+
1062
+ Set or clear Message Waiting Indicator (MWI) for a person or workspace. Service App only.
1063
+
1064
+ ```
1065
+ POST /v1/telephony/externalVoicemail/mwi?id={userId}&orgId={orgId}
1066
+ ```
1067
+
1068
+ **SDK Signature:**
1069
+ ```python
1070
+ CallsApi.update_external_voicemail_mwi(
1071
+ id: str, # person or workspace ID
1072
+ action: ExternalVoicemailMwiAction, # 'SET' or 'CLEAR'
1073
+ org_id: str = None
1074
+ ) -> None
1075
+ ```
1076
+
1077
+ **Scope required:** `spark-admin:calls_write`
1078
+
1079
+ ### CLI: `external-voicemail` (MWI Control)
1080
+
1081
+ The `external-voicemail` CLI group sets or clears the Message Waiting Indicator (MWI) for a person or workspace. Requires a Service App token with `spark-admin:calls_write` scope.
1082
+
1083
+ | Command | Description |
1084
+ |---------|-------------|
1085
+ | `external-voicemail create` | Set or clear MWI status for a user or workspace |
1086
+
1087
+ ```bash
1088
+ # Set MWI (light the voicemail indicator) for a user
1089
+ wxcli external-voicemail create --id <person_id> --action SET
1090
+
1091
+ # Clear MWI (turn off the voicemail indicator) for a user
1092
+ wxcli external-voicemail create --id <person_id> --action CLEAR
1093
+
1094
+ # Set MWI for a workspace phone
1095
+ wxcli external-voicemail create --id <workspace_id> --action SET
1096
+ ```
1097
+
1098
+ ---
1099
+
1100
+ ## 7. Common Use Cases
1101
+
1102
+ ### Click-to-Dial from CRM
1103
+ ```python
1104
+ from wxc_sdk import WebexSimpleApi
1105
+
1106
+ api = WebexSimpleApi(tokens=tokens)
1107
+
1108
+ # Place a call from the CRM contact page
1109
+ result = api.telephony.calls.dial(destination="+12223334444")
1110
+ print(f"Call initiated: {result.call_id}")
1111
+ ```
1112
+
1113
+ ### Agent Dashboard: List Active Calls
1114
+ ```python
1115
+ calls = api.telephony.calls.list_calls()
1116
+ for call in calls:
1117
+ print(f"{call.call_id} | {call.state} | {call.remote_party.name} ({call.remote_party.number})")
1118
+ ```
1119
+
1120
+ ### Consultative Transfer
1121
+ ```python
1122
+ # Agent has two calls: original caller and the transfer target
1123
+ # Transfer them together
1124
+ api.telephony.calls.transfer(call_id1=original_call_id, call_id2=consult_call_id)
1125
+ ```
1126
+
1127
+ ### Hold, Consult, Transfer Pattern
1128
+ ```python
1129
+ # 1. Put caller on hold
1130
+ api.telephony.calls.hold(call_id=caller_call_id)
1131
+
1132
+ # 2. Dial the transfer target
1133
+ consult = api.telephony.calls.dial(destination="+15551234567")
1134
+
1135
+ # 3. After speaking with transfer target, transfer both calls
1136
+ api.telephony.calls.transfer(call_id1=caller_call_id, call_id2=consult.call_id)
1137
+ ```
1138
+
1139
+ ### Park and Retrieve
1140
+ ```python
1141
+ # Park the call
1142
+ parked = api.telephony.calls.park(call_id=call_id)
1143
+ print(f"Parked against: {parked.number}")
1144
+
1145
+ # Later, retrieve it (from any device)
1146
+ retrieved = api.telephony.calls.retrieve(destination=parked.number)
1147
+ ```
1148
+
1149
+ ### Call Recording Control
1150
+ ```python
1151
+ # Start recording (user must have "On Demand" recording mode)
1152
+ api.telephony.calls.start_recording(call_id=call_id)
1153
+
1154
+ # Pause for sensitive info (credit card, SSN)
1155
+ api.telephony.calls.pause_recording(call_id=call_id)
1156
+
1157
+ # Resume
1158
+ api.telephony.calls.resume_recording(call_id=call_id)
1159
+
1160
+ # Stop
1161
+ api.telephony.calls.stop_recording(call_id=call_id)
1162
+ ```
1163
+
1164
+ ### Service App: Control Calls for a User
1165
+ ```python
1166
+ # Using admin/service app credentials with spark-admin:calls_write
1167
+ from wxc_sdk.telephony.call_contols_members import CallControlsMembersApi
1168
+
1169
+ # Dial on behalf of a user
1170
+ result = members_api.dial(
1171
+ member_id="person-uuid-here",
1172
+ destination="+12223334444"
1173
+ )
1174
+ ```
1175
+
1176
+ ---
1177
+
1178
+ ## 8. Key Gotchas
1179
+
1180
+ 1. **3rd Party Call Control only** -- These APIs do not work with Webex app's native calling. They are for building external call control applications.
1181
+
1182
+ 2. **Multi-Tenant only** -- Not applicable for UCM or Dedicated Instance users.
1183
+
1184
+ 3. **Service Apps cannot use CallsApi** -- Service Apps must use the `CallControlsMembersApi` (members endpoint) instead.
1185
+
1186
+ 4. **`callId` vs `id`** -- The API returns `id` in direct call responses but `callId` in webhook events. The SDK's `TelephonyCall` model handles both aliases transparently via the `call_id` property.
1187
+
1188
+ 5. **Click-to-Dial personality transition** -- A dial request starts with `personality: clickToDial` while alerting the user's devices. Once the user answers, it transitions to `personality: originator`.
1189
+
1190
+ 6. **Transfer restrictions** -- Unanswered incoming calls cannot be transferred. Use `divert` for unanswered calls.
1191
+
1192
+ 7. **`lineOwnerId` parameter** -- Present on nearly all methods. Used when the API caller has a secondary line belonging to another user, workspace, or virtual line on their device.
1193
+
1194
+ 8. **Recording mode dependency** -- `start_recording` / `stop_recording` only work when the user's recording mode is "On Demand". `pause_recording` / `resume_recording` work with both "On Demand" and "Always with Pause/Resume".
1195
+
1196
+ 9. **Mute capability check** -- Always check `muteCapable` in call details before calling `mute` or `unmute`. Not all calls support it.
1197
+
1198
+ 10. **Call history limit** -- `call_history` returns a maximum of 20 records per type (placed/missed/received).
1199
+
1200
+ ---
1201
+
1202
+ ## See Also
1203
+
1204
+ - **[webhooks-events.md](webhooks-events.md)** — Real-time call event notifications via webhooks. The `TelephonyEventData` model inherits from `TelephonyCall` documented here; use webhooks for event-driven call control rather than polling `list_calls`.
1205
+ - **[person-call-settings-media.md](person-call-settings-media.md)** — Call recording configuration (recording mode, compliance announcements). Recording mode determines which recording control actions are available in this API.