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,2037 @@
1
+ # Location Call Settings — Core Settings & Voicemail
2
+
3
+ ## Sources
4
+ - wxc_sdk v1.30.0
5
+ - OpenAPI spec: specs/webex-cloud-calling.json
6
+ - developer.webex.com Location Call Settings APIs
7
+
8
+ Reference document covering the SDK APIs for location-level call settings, voicemail policies (location and org), voicemail rules, voice messaging, and voice portal configuration.
9
+
10
+ **SDK source module:** `wxc_sdk.telephony.location` (and related telephony modules)
11
+
12
+ ---
13
+
14
+ ## Table of Contents
15
+
16
+ 1. [Location-Level Call Settings](#1-location-level-call-settings)
17
+ - [TelephonyLocationApi — Main API Class](#telephonylocationapi--main-api-class)
18
+ - [Data Models](#location-data-models)
19
+ - [Enable / List / Get / Update Locations](#enable--list--get--update-locations)
20
+ - [Caller ID](#caller-id)
21
+ - [Internal Dialing](#internal-dialing)
22
+ - [Call Intercept](#call-intercept)
23
+ - [Music on Hold](#music-on-hold)
24
+ - [Location Numbers](#location-numbers)
25
+ - [Emergency Callback Number (ECBN)](#emergency-callback-number-ecbn)
26
+ - [Announcement Language](#announcement-language)
27
+ - [Call Captions](#call-captions)
28
+ - [Device Settings](#device-settings)
29
+ - [Safe Delete Check](#safe-delete-check)
30
+ - [Extension Validation & Password Generation](#extension-validation--password-generation)
31
+ 2. [Voicemail Policies](#2-voicemail-policies)
32
+ - [Location Voicemail Settings](#location-voicemail-settings)
33
+ - [Organisation Voicemail Settings](#organisation-voicemail-settings)
34
+ 3. [Voicemail Rules (Org-Level Passcode Policy)](#3-voicemail-rules-org-level-passcode-policy)
35
+ 4. [Voice Messaging (User-Level)](#4-voice-messaging-user-level)
36
+ 5. [Voice Portal](#5-voice-portal)
37
+
38
+ ---
39
+
40
+ ## 1. Location-Level Call Settings
41
+
42
+ ### TelephonyLocationApi -- Main API Class
43
+
44
+ The main entry point is `TelephonyLocationApi`, accessible at `api.telephony.location`. It aggregates several child APIs as attributes:
45
+
46
+ ```
47
+ base = 'telephony/config/locations'
48
+ ```
49
+
50
+ | Attribute | Type | Purpose |
51
+ |-----------|------|---------|
52
+ | `emergency_services` | `LocationEmergencyServicesApi` | Emergency services config |
53
+ | `intercept` | `LocationInterceptApi` | Call intercept settings |
54
+ | `internal_dialing` | `InternalDialingApi` | Internal dialing / unknown extension routing |
55
+ | `moh` | `LocationMoHApi` | Music on hold settings |
56
+ | `number` | `LocationNumbersApi` | Phone number management (add/remove/activate) |
57
+ | `permissions_out` | `OutgoingPermissionsApi` | Outgoing call permissions |
58
+ | `voicemail` | `LocationVoicemailSettingsApi` | Location VM settings (transcription toggle) |
59
+ | `receptionist_contacts_directory` | `ReceptionistContactsDirectoryApi` | Receptionist contact directories |
60
+
61
+ ---
62
+
63
+ ### Location Data Models
64
+
65
+ #### `TelephonyLocation`
66
+
67
+ The core model representing a Webex Calling-enabled location.
68
+
69
+ | Field | Type | Description |
70
+ |-------|------|-------------|
71
+ | `location_id` | `str` | Unique identifier (aliased from `id`) |
72
+ | `name` | `str` | Location name |
73
+ | `announcement_language` | `str` | Phone announcement language |
74
+ | `calling_line_id` | `CallingLineId` | Caller ID name + phone number |
75
+ | `connection` | `PSTNConnection` | PSTN connection (TRUNK or ROUTE_GROUP) |
76
+ | `subscription_id` | `str` | PSTN subscription ID |
77
+ | `external_caller_id_name` | `str` | External caller ID name (Unicode) |
78
+ | `user_limit` | `int` | Max people at location (read-only) |
79
+ | `p_access_network_info` | `str` | Emergency SIP P-Access-Network-Info header |
80
+ | `outside_dial_digit` | `str` | Digit to dial for outside line (e.g. `'9'`) |
81
+ | `enforce_outside_dial_digit` | `bool` | Enforce outside dial digit for PSTN calls |
82
+ | `routing_prefix` | `str` | Prefix for inter-location calls with same extension |
83
+ | `default_domain` | `str` | IP/hostname/domain (read-only) |
84
+ | `charge_number` | `str` | P-Charge-Info header number for PSTN calls |
85
+ | `use_charge_number_for_pcharge_info` | `bool` | Enable charge number in SIP INVITE |
86
+ | `e911_setup_required` | `bool` | Whether E911 setup is needed (read-only) |
87
+
88
+ **Read-only fields** (excluded from updates): `location_id`, `name`, `subscription_id`, `user_limit`, `default_domain`, `e911_setup_required`.
89
+
90
+ #### `CallingLineId`
91
+
92
+ | Field | Type | Description |
93
+ |-------|------|-------------|
94
+ | `name` | `str` | Group calling line ID name (defaults to org name). When updating, include phone_number too. |
95
+ | `phone_number` | `str` | Main number in E.164 format |
96
+
97
+ #### `PSTNConnection`
98
+
99
+ | Field | Type | Description |
100
+ |-------|------|-------------|
101
+ | `type` | `RouteType` | `TRUNK` or `ROUTE_GROUP` |
102
+ | `id` | `str` | Unique identifier of the route |
103
+
104
+ ---
105
+
106
+ ### Enable / List / Get / Update Locations
107
+
108
+ #### `enable_for_calling`
109
+
110
+ Enable a location for Webex Calling. Adds calling support to a location created via the locations API.
111
+
112
+ ```python
113
+ def enable_for_calling(
114
+ self,
115
+ location: Location,
116
+ org_id: str = None
117
+ ) -> str
118
+ ```
119
+
120
+ **Returns:** The new location ID.
121
+
122
+ **Scope:** `spark-admin:telephony_config_write`
123
+
124
+ ---
125
+
126
+ #### `list`
127
+
128
+ List all Webex Calling locations with telephony details.
129
+
130
+ ```python
131
+ def list(
132
+ self,
133
+ name: str = None,
134
+ order: str = None,
135
+ org_id: str = None
136
+ ) -> Generator[TelephonyLocation, None, None]
137
+ ```
138
+
139
+ | Parameter | Description |
140
+ |-----------|-------------|
141
+ | `name` | Filter — locations whose name contains this string |
142
+ | `order` | Sort by name: `'asc'` or `'desc'` |
143
+
144
+ **Scope:** `spark-admin:telephony_config_read`
145
+
146
+ ---
147
+
148
+ #### `details`
149
+
150
+ Get Webex Calling details for a single location.
151
+
152
+ ```python
153
+ def details(
154
+ self,
155
+ location_id: str,
156
+ org_id: str = None
157
+ ) -> TelephonyLocation
158
+ ```
159
+
160
+ **Scope:** `spark-admin:telephony_config_read`
161
+
162
+ ---
163
+
164
+ #### `update`
165
+
166
+ Update Webex Calling details for a location. Only non-read-only fields in `TelephonyLocation` are sent.
167
+
168
+ ```python
169
+ def update(
170
+ self,
171
+ location_id: str,
172
+ settings: TelephonyLocation,
173
+ org_id: str = None
174
+ ) -> Optional[str]
175
+ ```
176
+
177
+ **Returns:** `batchJobId` if an async update job is created, otherwise `None`.
178
+
179
+ **Example:**
180
+ ```python
181
+ api.telephony.location.update(
182
+ location_id=location_id,
183
+ settings=TelephonyLocation(
184
+ calling_line_id=CallingLineId(phone_number=tn),
185
+ routing_prefix=routing_prefix,
186
+ outside_dial_digit='9'
187
+ )
188
+ )
189
+ ```
190
+
191
+ **Scope:** `spark-admin:telephony_config_write`
192
+
193
+ **Note:** Modifying `connection` is only supported for local PSTN types `TRUNK` and `ROUTE_GROUP`.
194
+
195
+ #### CLI Examples
196
+
197
+ ```bash
198
+ # List all locations with Webex Calling details
199
+ wxcli location-settings list-1
200
+
201
+ # List locations filtered by name
202
+ wxcli location-settings list-1 --name "San Jose"
203
+
204
+ # Get calling details for a specific location
205
+ wxcli location-settings show Y2lzY29zcGFyazovL...
206
+
207
+ # Enable a location for Webex Calling
208
+ wxcli location-settings create \
209
+ --id Y2lzY29zcGFyazovL... \
210
+ --name "San Jose HQ" \
211
+ --time-zone "America/Los_Angeles" \
212
+ --preferred-language "en_us" \
213
+ --announcement-language "en_us"
214
+
215
+ # Update location calling details (outside dial digit, routing prefix)
216
+ wxcli location-settings update Y2lzY29zcGFyazovL... \
217
+ --outside-dial-digit "9" \
218
+ --enforce-outside-dial-digit \
219
+ --routing-prefix "8001" \
220
+ --external-caller-id-name "Acme Corp"
221
+
222
+ # Update location with JSON body for complex settings
223
+ wxcli location-settings update Y2lzY29zcGFyazovL... \
224
+ --json-body '{"announcementLanguage": "en_us", "chargeNumber": "+14085551234"}'
225
+ ```
226
+
227
+ ---
228
+
229
+ ### Caller ID
230
+
231
+ Caller ID is configured through the `CallingLineId` object embedded in `TelephonyLocation`. There is also a dedicated API to list phone numbers available for external caller ID.
232
+
233
+ #### `phone_numbers_available_for_external_caller_id`
234
+
235
+ List phone numbers available for external caller ID usage by a Webex Calling entity within a location.
236
+
237
+ ```python
238
+ def phone_numbers_available_for_external_caller_id(
239
+ self,
240
+ location_id: str,
241
+ phone_number: List[str] = None,
242
+ owner_name: str = None,
243
+ person_id: str = None,
244
+ org_id: str = None,
245
+ **params
246
+ ) -> Generator[AvailableNumber, None, None]
247
+ ```
248
+
249
+ Numbers from the specified location and cross-location numbers (same country, PSTN provider, zone) are returned. When `person_id` is specified for a Cisco PSTN location user with a mobile primary DN and no billing plan, only that mobile number is returned.
250
+
251
+ **Scope:** `spark-admin:telephony_config_read`
252
+
253
+ ---
254
+
255
+ ### Internal Dialing
256
+
257
+ **API path:** `api.telephony.location.internal_dialing`
258
+
259
+ Controls routing of calls to unknown extensions (2-6 digits) to a premises PBX via a trunk or route group.
260
+
261
+ #### `InternalDialing` Model
262
+
263
+ | Field | Type | Description |
264
+ |-------|------|-------------|
265
+ | `enable_unknown_extension_route_policy` | `bool` | Route unknown extensions to premises |
266
+ | `unknown_extension_route_identity` | `RouteIdentity` | Destination trunk/route group for unknown extensions |
267
+
268
+ #### `read`
269
+
270
+ ```python
271
+ def read(
272
+ self,
273
+ location_id: str,
274
+ org_id: str = None
275
+ ) -> InternalDialing
276
+ ```
277
+
278
+ **Scope:** `spark-admin:telephony_config_read`
279
+
280
+ #### `update`
281
+
282
+ ```python
283
+ def update(
284
+ self,
285
+ location_id: str,
286
+ update: InternalDialing,
287
+ org_id: str = None
288
+ )
289
+ ```
290
+
291
+ **Scope:** `spark-admin:telephony_config_write`
292
+
293
+ #### CLI Examples
294
+
295
+ ```bash
296
+ # Read internal dialing configuration for a location
297
+ wxcli location-call-handling show Y2lzY29zcGFyazovL...
298
+
299
+ # Enable routing of unknown extensions to a trunk
300
+ wxcli location-call-handling update Y2lzY29zcGFyazovL... \
301
+ --enable-unknown-extension-route-policy \
302
+ --json-body '{"unknownExtensionRouteIdentity": {"id": "TRUNK_ID", "type": "TRUNK"}}'
303
+
304
+ # Disable unknown extension routing
305
+ wxcli location-call-handling update Y2lzY29zcGFyazovL... \
306
+ --no-enable-unknown-extension-route-policy
307
+ ```
308
+
309
+ ---
310
+
311
+ ### Call Intercept
312
+
313
+ **API path:** `api.telephony.location.intercept`
314
+
315
+ Intercept incoming or outgoing calls for all persons at a location. Intercepted calls are routed to a designated number or to voicemail.
316
+
317
+ Uses the shared `InterceptSetting` model from `wxc_sdk.person_settings.call_intercept`.
318
+
319
+ #### `read`
320
+
321
+ ```python
322
+ def read(
323
+ self,
324
+ location_id: str,
325
+ org_id: str = None
326
+ ) -> InterceptSetting
327
+ ```
328
+
329
+ **Scope:** `spark-admin:telephony_config_read`
330
+
331
+ #### `configure`
332
+
333
+ ```python
334
+ def configure(
335
+ self,
336
+ location_id: str,
337
+ settings: InterceptSetting,
338
+ org_id: str = None
339
+ )
340
+ ```
341
+
342
+ **Scope:** `spark-admin:telephony_config_write`
343
+
344
+ #### `call_intercept_available_phone_numbers`
345
+
346
+ (On `TelephonyLocationApi` directly.) List service and standard numbers available to be assigned as the location's call intercept number.
347
+
348
+ ```python
349
+ def call_intercept_available_phone_numbers(
350
+ self,
351
+ location_id: str,
352
+ phone_number: List[str] = None,
353
+ owner_name: str = None,
354
+ org_id: str = None,
355
+ **params
356
+ ) -> Generator[AvailableNumber, None, None]
357
+ ```
358
+
359
+ **Scope:** `spark-admin:telephony_config_read`
360
+
361
+ #### CLI Examples
362
+
363
+ ```bash
364
+ # Read call intercept settings for a location
365
+ wxcli location-call-handling show-intercept Y2lzY29zcGFyazovL...
366
+
367
+ # Enable call intercept for all users at a location
368
+ wxcli location-call-handling update-intercept Y2lzY29zcGFyazovL... --enabled
369
+
370
+ # Enable intercept with voicemail routing via JSON body
371
+ wxcli location-call-handling update-intercept Y2lzY29zcGFyazovL... \
372
+ --json-body '{"enabled": true, "incoming": {"type": "INTERCEPT_ALL", "voicemailEnabled": true}}'
373
+
374
+ # Disable call intercept
375
+ wxcli location-call-handling update-intercept Y2lzY29zcGFyazovL... --no-enabled
376
+
377
+ # List available phone numbers for call intercept
378
+ wxcli location-settings list-available-numbers-call-intercept Y2lzY29zcGFyazovL...
379
+ ```
380
+
381
+ ---
382
+
383
+ ### Music on Hold
384
+
385
+ **API path:** `api.telephony.location.moh`
386
+
387
+ Controls music played when a call is on hold or parked at the location.
388
+
389
+ #### `LocationMoHGreetingType` Enum
390
+
391
+ | Value | Description |
392
+ |-------|-------------|
393
+ | `SYSTEM` | Default system music |
394
+ | `CUSTOM` | Custom uploaded audio file or playlist |
395
+
396
+ #### `LocationMoHSetting` Model
397
+
398
+ | Field | Type | Description |
399
+ |-------|------|-------------|
400
+ | `call_hold_enabled` | `bool` | Play music on hold |
401
+ | `call_park_enabled` | `bool` | Play music on park |
402
+ | `greeting` | `LocationMoHGreetingType` | `SYSTEM` or `CUSTOM` |
403
+ | `audio_file` | `AnnAudioFile` | Audio file details (when `CUSTOM`) |
404
+ | `playlist` | `IdAndName` | Playlist details (when `CUSTOM`) |
405
+
406
+ #### `read`
407
+
408
+ ```python
409
+ def read(
410
+ self,
411
+ location_id: str,
412
+ org_id: str = None
413
+ ) -> LocationMoHSetting
414
+ ```
415
+
416
+ **Scope:** `spark-admin:telephony_config_read`
417
+
418
+ #### `update`
419
+
420
+ ```python
421
+ def update(
422
+ self,
423
+ location_id: str,
424
+ settings: LocationMoHSetting,
425
+ org_id: str = None
426
+ )
427
+ ```
428
+
429
+ **Scope:** `spark-admin:telephony_config_write`
430
+
431
+ #### CLI Examples
432
+
433
+ ```bash
434
+ # Read music on hold settings for a location
435
+ wxcli location-settings show-music-on-hold Y2lzY29zcGFyazovL...
436
+
437
+ # Enable music on hold with system greeting
438
+ wxcli location-settings update-music-on-hold Y2lzY29zcGFyazovL... \
439
+ --moh-enabled --greeting DEFAULT
440
+
441
+ # Switch to custom greeting
442
+ wxcli location-settings update-music-on-hold Y2lzY29zcGFyazovL... \
443
+ --moh-enabled --greeting CUSTOM
444
+ ```
445
+
446
+ ---
447
+
448
+ ### Location Numbers
449
+
450
+ **API path:** `api.telephony.location.number`
451
+
452
+ Manage phone numbers assigned to a location (add, remove, activate, deactivate).
453
+
454
+ #### Key Models
455
+
456
+ | Model | Description |
457
+ |-------|-------------|
458
+ | `TelephoneNumberType` | Enum: `TOLLFREE`, `DID`, `MOBILE` |
459
+ | `NumberUsageType` | Enum: `NONE` (standard), `SERVICE` (high-volume, e.g. Contact Center) |
460
+ | `NumbersRequestAction` | Enum: `ACTIVATE`, `DEACTIVATE` |
461
+
462
+ #### `add`
463
+
464
+ ```python
465
+ def add(
466
+ self,
467
+ location_id: str,
468
+ phone_numbers: list[str],
469
+ number_type: TelephoneNumberType = None,
470
+ number_usage_type: NumberUsageType = None,
471
+ state: NumberState = NumberState.inactive,
472
+ subscription_id: str = None,
473
+ carrier_id: str = None,
474
+ org_id: str = None
475
+ ) -> NumberAddResponse
476
+ ```
477
+
478
+ Only supported for non-integrated PSTN (LGW, Non-integrated CPP). Max 20 mobile numbers per request. Numbers already at the location are silently ignored.
479
+
480
+ #### `remove`
481
+
482
+ ```python
483
+ def remove(
484
+ self,
485
+ location_id: str,
486
+ phone_numbers: list[str],
487
+ org_id: str = None
488
+ )
489
+ ```
490
+
491
+ A location's main number cannot be removed. Only non-integrated PSTN.
492
+
493
+ #### `activate`
494
+
495
+ ```python
496
+ def activate(
497
+ self,
498
+ location_id: str,
499
+ phone_numbers: list[str],
500
+ org_id: str = None
501
+ )
502
+ ```
503
+
504
+ Does not activate mobile numbers (those activate on user assignment).
505
+
506
+ #### `manage_number_state`
507
+
508
+ ```python
509
+ def manage_number_state(
510
+ self,
511
+ location_id: str,
512
+ phone_numbers: list[str],
513
+ action: NumbersRequestAction = None,
514
+ org_id: str = None
515
+ )
516
+ ```
517
+
518
+ Unified activate/deactivate. Deactivate limitations: max 500 numbers, must be unassigned, not ECBN, not mobile, non-integrated PSTN only.
519
+
520
+ ---
521
+
522
+ ### Emergency Callback Number (ECBN)
523
+
524
+ #### `read_ecbn`
525
+
526
+ ```python
527
+ def read_ecbn(
528
+ self,
529
+ location_id: str,
530
+ org_id: str = None
531
+ ) -> LocationECBN
532
+ ```
533
+
534
+ **Scope:** `spark-admin:telephony_config_read`
535
+
536
+ #### `update_ecbn`
537
+
538
+ ```python
539
+ def update_ecbn(
540
+ self,
541
+ location_id: str,
542
+ selected: CallBackSelected,
543
+ location_member_id: str = None,
544
+ org_id: str = None
545
+ )
546
+ ```
547
+
548
+ | `CallBackSelected` Value | Description |
549
+ |--------------------------|-------------|
550
+ | `LOCATION_NUMBER` | Use the location's TN |
551
+ | `LOCATION_MEMBER_NUMBER` | Use a member's number (requires `location_member_id`) |
552
+
553
+ **Scope:** `spark-admin:telephony_config_write`
554
+
555
+ #### `ecbn_available_phone_numbers`
556
+
557
+ ```python
558
+ def ecbn_available_phone_numbers(
559
+ self,
560
+ location_id: str,
561
+ phone_number: List[str] = None,
562
+ owner_name: str = None,
563
+ org_id: str = None,
564
+ **params
565
+ ) -> Generator[AvailableNumber, None, None]
566
+ ```
567
+
568
+ #### `LocationECBN` Model
569
+
570
+ | Field | Type | Description |
571
+ |-------|------|-------------|
572
+ | `location_info` | `LocationECBNLocation` | Location-level ECBN data (phone_number, name, effective_level, effective_value, quality) |
573
+ | `location_member_info` | `LocationECBNLocationMember` | Member-level ECBN data (phone_number, first/last name, member_id, member_type, effective_level, effective_value, quality) |
574
+ | `selected` | `CallBackSelected` | Which number type is selected |
575
+
576
+ #### CLI Examples
577
+
578
+ ```bash
579
+ # Read ECBN settings for a location
580
+ wxcli location-settings show-emergency-callback-number Y2lzY29zcGFyazovL...
581
+
582
+ # Update ECBN to use the location's main number
583
+ wxcli location-settings update-emergency-callback-number Y2lzY29zcGFyazovL... \
584
+ --json-body '{"selected": "LOCATION_NUMBER"}'
585
+
586
+ # Update ECBN to use a specific member's number
587
+ wxcli location-settings update-emergency-callback-number Y2lzY29zcGFyazovL... \
588
+ --location-member-id MEMBER_ID \
589
+ --json-body '{"selected": "LOCATION_MEMBER_NUMBER", "locationMemberId": "MEMBER_ID"}'
590
+
591
+ # List available ECBN phone numbers
592
+ wxcli location-settings list-available-numbers-emergency-callback-number Y2lzY29zcGFyazovL...
593
+ ```
594
+
595
+ ---
596
+
597
+ ### Announcement Language
598
+
599
+ #### `change_announcement_language`
600
+
601
+ Change the announcement language for existing people/workspaces and/or feature configurations at a location. Does **not** change the default language for new entities.
602
+
603
+ ```python
604
+ def change_announcement_language(
605
+ self,
606
+ location_id: str,
607
+ language_code: str,
608
+ agent_enabled: bool = None,
609
+ service_enabled: bool = None,
610
+ org_id: str = None
611
+ )
612
+ ```
613
+
614
+ | Parameter | Description |
615
+ |-----------|-------------|
616
+ | `language_code` | Language code to set |
617
+ | `agent_enabled` | `True` to change language for existing people/workspaces |
618
+ | `service_enabled` | `True` to change language for existing feature configurations |
619
+
620
+ **Scope:** `spark-admin:telephony_config_write`
621
+
622
+ #### CLI Examples
623
+
624
+ ```bash
625
+ # Change announcement language for existing people and features at a location
626
+ wxcli location-settings change-announcement-language Y2lzY29zcGFyazovL... \
627
+ --announcement-language-code "en_us" \
628
+ --agent-enabled true \
629
+ --service-enabled true
630
+ ```
631
+
632
+ ---
633
+
634
+ ### Call Captions
635
+
636
+ #### `LocationCallCaptions` Model
637
+
638
+ | Field | Type | Description |
639
+ |-------|------|-------------|
640
+ | `location_closed_captions_enabled` | `bool` | Location-level closed captions on/off |
641
+ | `location_transcripts_enabled` | `bool` | Location-level transcripts on/off |
642
+ | `org_closed_captions_enabled` | `bool` | Org-level closed captions (read-only) |
643
+ | `org_transcripts_enabled` | `bool` | Org-level transcripts (read-only) |
644
+ | `use_org_settings_enabled` | `bool` | `True` = org settings override location settings |
645
+
646
+ **Note:** Not supported for locations in India.
647
+
648
+ #### `get_call_captions_settings`
649
+
650
+ ```python
651
+ def get_call_captions_settings(
652
+ self,
653
+ location_id: str,
654
+ org_id: str = None
655
+ ) -> LocationCallCaptions
656
+ ```
657
+
658
+ #### `update_call_captions_settings`
659
+
660
+ ```python
661
+ def update_call_captions_settings(
662
+ self,
663
+ location_id: str,
664
+ settings: LocationCallCaptions,
665
+ org_id: str = None
666
+ )
667
+ ```
668
+
669
+ Only location-level fields and `use_org_settings_enabled` are sent on update; org-level fields are excluded.
670
+
671
+ #### CLI Examples
672
+
673
+ ```bash
674
+ # Read call captions settings for a location
675
+ wxcli location-settings show-call-captions Y2lzY29zcGFyazovL...
676
+
677
+ # Enable location-level closed captions and transcripts
678
+ wxcli location-settings update-call-captions Y2lzY29zcGFyazovL... \
679
+ --location-closed-captions-enabled \
680
+ --location-transcripts-enabled \
681
+ --no-use-org-settings-enabled
682
+
683
+ # Use org-level settings instead of location overrides
684
+ wxcli location-settings update-call-captions Y2lzY29zcGFyazovL... \
685
+ --use-org-settings-enabled
686
+ ```
687
+
688
+ ---
689
+
690
+ ### Device Settings
691
+
692
+ #### `device_settings`
693
+
694
+ Get device override settings for a location.
695
+
696
+ ```python
697
+ def device_settings(
698
+ self,
699
+ location_id: str,
700
+ org_id: str = None
701
+ ) -> DeviceCustomization
702
+ ```
703
+
704
+ **Scope:** `spark-admin:telephony_config_read`
705
+
706
+ ---
707
+
708
+ ### Safe Delete Check
709
+
710
+ #### `safe_delete_check_before_disabling_calling_location`
711
+
712
+ Check whether a calling location can be safely disabled. Returns blockers and warnings.
713
+
714
+ ```python
715
+ def safe_delete_check_before_disabling_calling_location(
716
+ self,
717
+ location_id: str,
718
+ org_id: str = None
719
+ ) -> SafeDeleteCheckResponse
720
+ ```
721
+
722
+ #### `SafeDeleteCheckResponse` Model
723
+
724
+ | Field | Type | Description |
725
+ |-------|------|-------------|
726
+ | `location_delete_status` | `LocationDeleteStatus` | `BLOCKED`, `UNBLOCKED`, or `FORCE_REQUIRED` |
727
+ | `blocking` | `BlockingDisableCalling` | Hard blockers: last_location, trunks_in_use_count, users_in_use_count, workspaces_in_use_count, virtual_line_in_use_count, numbers_order_pending |
728
+ | `non_blocking` | `NonBlockingDisableCalling` | Warnings: numbers_present |
729
+ | `blocking_unless_forced` | `BlockingUnlessForced` | Soft blockers: non_user_entities_in_use, trunks_count |
730
+
731
+ **Scope:** `spark-admin:telephony_config_read`
732
+
733
+ #### CLI Examples
734
+
735
+ ```bash
736
+ # Check if a location can be safely disabled for calling
737
+ wxcli location-settings safe-delete-check Y2lzY29zcGFyazovL...
738
+ ```
739
+
740
+ ---
741
+
742
+ ### Extension Validation & Password Generation
743
+
744
+ #### `validate_extensions`
745
+
746
+ ```python
747
+ def validate_extensions(
748
+ self,
749
+ location_id: str,
750
+ extensions: list[str],
751
+ org_id: str = None
752
+ ) -> ValidateExtensionsResponse
753
+ ```
754
+
755
+ **Scope:** `spark-admin:telephony_config_write`
756
+
757
+ #### `generate_password`
758
+
759
+ Generate an example SIP password using the location's effective password settings. Used during trunk creation.
760
+
761
+ ```python
762
+ def generate_password(
763
+ self,
764
+ location_id: str,
765
+ generate: list[str] = None,
766
+ org_id: str = None
767
+ ) -> str
768
+ ```
769
+
770
+ **Returns:** The generated example SIP password string.
771
+
772
+ **Scope:** `spark-admin:telephony_config_write`
773
+
774
+ #### CLI Examples
775
+
776
+ ```bash
777
+ # Validate extensions at a location
778
+ wxcli location-settings validate-extensions Y2lzY29zcGFyazovL... \
779
+ --json-body '{"extensions": ["1000", "1001", "1002"]}'
780
+
781
+ # Generate an example SIP password for a location
782
+ wxcli location-call-handling generate-example-password Y2lzY29zcGFyazovL...
783
+ ```
784
+
785
+ ---
786
+
787
+ ### Raw HTTP
788
+ <!-- Updated by playbook session 2026-03-18 -->
789
+
790
+ ```python
791
+ from wxc_sdk import WebexSimpleApi
792
+ api = WebexSimpleApi() # auth via WEBEX_ACCESS_TOKEN env var
793
+ BASE = "https://webexapis.com/v1"
794
+ ```
795
+
796
+ All location-level call settings use raw HTTP via `api.session.rest_*()` methods. Full URLs are required. No auto-pagination -- pass `max=1000` for list endpoints. Responses are JSON dicts. Errors raise `RestError`.
797
+
798
+ #### Location Calling Config (List / Get / Enable / Update)
799
+
800
+ **List locations with calling details:**
801
+ ```python
802
+ params = {"max": 1000}
803
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations", params=params)
804
+ locations = result.get("locations", [])
805
+ # Each item: {"id", "name", "announcementLanguage", "callingLineId", "connection", ...}
806
+ ```
807
+
808
+ **Get a single location's calling details:**
809
+ ```python
810
+ loc = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}")
811
+ ```
812
+
813
+ **Enable a location for calling:**
814
+ ```python
815
+ body = {
816
+ "id": location_id, # existing location ID from Locations API
817
+ "name": "San Jose HQ",
818
+ "timeZone": "America/Los_Angeles",
819
+ "preferredLanguage": "en_us",
820
+ "announcementLanguage": "en_us"
821
+ }
822
+ result = api.session.rest_post(f"{BASE}/telephony/config/locations", json=body)
823
+ ```
824
+
825
+ **Update location calling details:**
826
+ ```python
827
+ body = {
828
+ "announcementLanguage": "en_us",
829
+ "outsideDialDigit": "9",
830
+ "enforceOutsideDialDigit": True,
831
+ "routingPrefix": "8001",
832
+ "externalCallerIdName": "Acme Corp"
833
+ }
834
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}", json=body)
835
+ # Returns batchJobId if async update, otherwise None
836
+ ```
837
+
838
+ #### Internal Dialing
839
+
840
+ **Read internal dialing settings:**
841
+ ```python
842
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/internalDialing")
843
+ # {"enableUnknownExtensionRoutePolicy": bool, "unknownExtensionRouteIdentity": {...}}
844
+ ```
845
+
846
+ **Update internal dialing:**
847
+ ```python
848
+ body = {
849
+ "enableUnknownExtensionRoutePolicy": True,
850
+ "unknownExtensionRouteIdentity": {"id": trunk_id, "type": "TRUNK"}
851
+ }
852
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/internalDialing", json=body)
853
+ ```
854
+
855
+ #### Call Intercept
856
+
857
+ **Read call intercept:**
858
+ ```python
859
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/intercept")
860
+ ```
861
+
862
+ **Update call intercept:**
863
+ ```python
864
+ body = {"enabled": True, "incoming": {"type": "INTERCEPT_ALL", "voicemailEnabled": True}}
865
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/intercept", json=body)
866
+ ```
867
+
868
+ **Available intercept phone numbers:**
869
+ ```python
870
+ result = api.session.rest_get(
871
+ f"{BASE}/telephony/config/locations/{loc_id}/callIntercept/availableNumbers",
872
+ params={"max": 1000}
873
+ )
874
+ numbers = result.get("availableNumbers", [])
875
+ ```
876
+
877
+ #### Music on Hold
878
+
879
+ **Read MoH settings:**
880
+ ```python
881
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/musicOnHold")
882
+ # {"mohEnabled": bool, "greeting": "SYSTEM"|"CUSTOM", "audioFile": {...}, "playlist": {...}}
883
+ ```
884
+
885
+ **Update MoH:**
886
+ ```python
887
+ body = {"mohEnabled": True, "greeting": "SYSTEM"}
888
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/musicOnHold", json=body)
889
+ ```
890
+
891
+ #### Emergency Callback Number (ECBN)
892
+
893
+ **Read ECBN:**
894
+ ```python
895
+ result = api.session.rest_get(
896
+ f"{BASE}/telephony/config/locations/{loc_id}/features/emergencyCallbackNumber"
897
+ )
898
+ ```
899
+
900
+ **Update ECBN:**
901
+ ```python
902
+ body = {"selected": "LOCATION_NUMBER"}
903
+ # Or: {"selected": "LOCATION_MEMBER_NUMBER", "locationMemberId": member_id}
904
+ api.session.rest_put(
905
+ f"{BASE}/telephony/config/locations/{loc_id}/features/emergencyCallbackNumber", json=body
906
+ )
907
+ ```
908
+
909
+ **ECBN available phone numbers:**
910
+ ```python
911
+ result = api.session.rest_get(
912
+ f"{BASE}/telephony/config/locations/{loc_id}/emergencyCallbackNumber/availableNumbers",
913
+ params={"max": 1000}
914
+ )
915
+ ```
916
+
917
+ #### Announcement Language
918
+
919
+ **Change announcement language for existing entities at a location:**
920
+ ```python
921
+ body = {
922
+ "announcementLanguageCode": "en_us",
923
+ "agentEnabled": True, # change for people/workspaces
924
+ "serviceEnabled": True # change for features (AA, CQ, etc.)
925
+ }
926
+ api.session.rest_post(
927
+ f"{BASE}/telephony/config/locations/{loc_id}/actions/modifyAnnouncementLanguage/invoke",
928
+ json=body
929
+ )
930
+ ```
931
+
932
+ > **Gotcha:** Use lowercase language codes (`en_us`, not `en_US`). The API rejects uppercase variants. Also, `announcementLanguage` may return `None` even when set -- this is a known API quirk.
933
+
934
+ #### Call Captions
935
+
936
+ **Read call captions settings:**
937
+ ```python
938
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callCaptions")
939
+ # {"locationClosedCaptionsEnabled", "locationTranscriptsEnabled",
940
+ # "orgClosedCaptionsEnabled", "orgTranscriptsEnabled", "useOrgSettingsEnabled"}
941
+ ```
942
+
943
+ **Update call captions:**
944
+ ```python
945
+ body = {
946
+ "locationClosedCaptionsEnabled": True,
947
+ "locationTranscriptsEnabled": True,
948
+ "useOrgSettingsEnabled": False
949
+ }
950
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/callCaptions", json=body)
951
+ ```
952
+
953
+ #### Device Settings
954
+
955
+ **Read location device overrides:**
956
+ ```python
957
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/devices/settings")
958
+ ```
959
+
960
+ #### Safe Delete Check
961
+
962
+ **Check if location can be safely disabled:**
963
+ ```python
964
+ result = api.session.rest_post(
965
+ f"{BASE}/telephony/config/locations/{loc_id}/actions/precheckForDeletion/invoke", json={}
966
+ )
967
+ # {"locationDeleteStatus": "BLOCKED"|"UNBLOCKED"|"FORCE_REQUIRED", "blocking": {...}, ...}
968
+ ```
969
+
970
+ **Disable a calling location (async job):**
971
+ ```python
972
+ body = {"locationId": loc_id, "locationName": "San Jose HQ", "forceDelete": False}
973
+ result = api.session.rest_post(
974
+ f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation", json=body
975
+ )
976
+ job_id = result.get("id")
977
+ ```
978
+
979
+ **Job management:**
980
+ ```python
981
+ # List jobs
982
+ api.session.rest_get(f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation")
983
+ # Get job status
984
+ api.session.rest_get(f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation/{job_id}")
985
+ # Get job errors
986
+ api.session.rest_get(f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation/{job_id}/errors")
987
+ # Pause job
988
+ api.session.rest_post(f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation/{job_id}/actions/pause/invoke", json={})
989
+ # Resume job
990
+ api.session.rest_post(f"{BASE}/telephony/config/jobs/locations/deleteCallingLocation/{job_id}/actions/resume/invoke", json={})
991
+ ```
992
+
993
+ #### CLI Examples — Disable Calling Location Jobs
994
+
995
+ ```bash
996
+ # Safe delete check before disabling a location
997
+ wxcli location-settings safe-delete-check Y2lzY29zcGFyazovL...
998
+
999
+ # Disable a calling location
1000
+ wxcli location-settings create-delete-calling-location \
1001
+ --location-id Y2lzY29zcGFyazovL... \
1002
+ --location-name "San Jose HQ"
1003
+
1004
+ # Force-disable a calling location (when features like trunks exist)
1005
+ wxcli location-settings create-delete-calling-location \
1006
+ --location-id Y2lzY29zcGFyazovL... \
1007
+ --location-name "San Jose HQ" \
1008
+ --force-delete
1009
+
1010
+ # List disable calling location jobs
1011
+ wxcli location-settings list-delete-calling-location
1012
+
1013
+ # Get disable calling location job status
1014
+ wxcli location-settings show-delete-calling-location JOB_ID
1015
+
1016
+ # Get job errors
1017
+ wxcli location-settings list-errors JOB_ID
1018
+
1019
+ # Pause a job
1020
+ wxcli location-settings pause-a-disable JOB_ID
1021
+
1022
+ # Resume a paused job
1023
+ wxcli location-settings resume-a-paused JOB_ID
1024
+ ```
1025
+
1026
+ #### Extension Validation
1027
+
1028
+ **Validate extensions at a location:**
1029
+ ```python
1030
+ body = {"extensions": ["1000", "1001", "1002"]}
1031
+ result = api.session.rest_post(
1032
+ f"{BASE}/telephony/config/locations/{loc_id}/actions/validateExtensions/invoke", json=body
1033
+ )
1034
+ ```
1035
+
1036
+ **Validate extensions org-wide:**
1037
+ ```python
1038
+ body = {"extensions": ["1000", "1001"]}
1039
+ result = api.session.rest_post(
1040
+ f"{BASE}/telephony/config/actions/validateExtensions/invoke", json=body
1041
+ )
1042
+ ```
1043
+
1044
+ #### Private Network Connect
1045
+
1046
+ **Read PNC settings:**
1047
+ ```python
1048
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/privateNetworkConnect")
1049
+ ```
1050
+
1051
+ **Update PNC settings:**
1052
+ ```python
1053
+ body = {"networkConnectionType": "PRIVATE_NETWORK"}
1054
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/privateNetworkConnect", json=body)
1055
+ ```
1056
+
1057
+ #### CLI Examples — Private Network Connect
1058
+
1059
+ ```bash
1060
+ # Read private network connect settings
1061
+ wxcli location-settings show-private-network-connect Y2lzY29zcGFyazovL...
1062
+
1063
+ # Update private network connect
1064
+ wxcli location-settings update-private-network-connect Y2lzY29zcGFyazovL... \
1065
+ --json-body '{"networkConnectionType": "PRIVATE_NETWORK"}'
1066
+ ```
1067
+
1068
+ #### Routing Prefix Jobs
1069
+
1070
+ **List update routing prefix jobs:**
1071
+ ```python
1072
+ result = api.session.rest_get(f"{BASE}/telephony/config/jobs/updateRoutingPrefix")
1073
+ ```
1074
+
1075
+ **Get job status / errors:**
1076
+ ```python
1077
+ api.session.rest_get(f"{BASE}/telephony/config/jobs/updateRoutingPrefix/{job_id}")
1078
+ api.session.rest_get(f"{BASE}/telephony/config/jobs/updateRoutingPrefix/{job_id}/errors")
1079
+ ```
1080
+
1081
+ #### Available Phone Numbers
1082
+
1083
+ Several endpoints return available phone numbers for different purposes. All follow the same pattern:
1084
+
1085
+ | Purpose | URL path |
1086
+ |---------|----------|
1087
+ | External Caller ID | `telephony/config/locations/{locId}/externalCallerId/availableNumbers` |
1088
+ | Location main number | `telephony/config/locations/{locId}/availableNumbers` |
1089
+ | Webex Go | `telephony/config/locations/{locId}/webexGo/availableNumbers` |
1090
+ | ECBN | `telephony/config/locations/{locId}/emergencyCallbackNumber/availableNumbers` |
1091
+ | Call Intercept | `telephony/config/locations/{locId}/callIntercept/availableNumbers` |
1092
+ | Charge Number | `telephony/config/locations/{locId}/chargeNumber/availableNumbers` |
1093
+ | Route Choices | `telephony/config/routeChoices` |
1094
+
1095
+ All accept `max`, `start`, `phoneNumber`, `ownerName` query params (availability varies by endpoint).
1096
+
1097
+ #### CLI Examples — Available Phone Numbers
1098
+
1099
+ ```bash
1100
+ # List phone numbers available for external caller ID
1101
+ wxcli location-settings list-available-numbers-external-caller-id Y2lzY29zcGFyazovL...
1102
+
1103
+ # List available phone numbers for a location's main number
1104
+ wxcli location-settings list-available-numbers-locations Y2lzY29zcGFyazovL...
1105
+
1106
+ # List Webex Go available phone numbers
1107
+ wxcli location-settings list-available-numbers-webex-go Y2lzY29zcGFyazovL...
1108
+
1109
+ # List available charge numbers
1110
+ wxcli location-settings list-available-numbers-charge-number Y2lzY29zcGFyazovL...
1111
+
1112
+ # List route choices
1113
+ wxcli location-settings list-route-choices
1114
+ ```
1115
+
1116
+ #### Receptionist Contact Directories
1117
+
1118
+ **Create directory:**
1119
+ ```python
1120
+ body = {"name": "Front Desk Contacts", "contacts": [{"id": person_id}]}
1121
+ result = api.session.rest_post(
1122
+ f"{BASE}/telephony/config/locations/{loc_id}/receptionistContacts/directories", json=body
1123
+ )
1124
+ new_id = result.get("id")
1125
+ ```
1126
+
1127
+ **List directories:**
1128
+ ```python
1129
+ result = api.session.rest_get(
1130
+ f"{BASE}/telephony/config/locations/{loc_id}/receptionistContacts/directories"
1131
+ )
1132
+ dirs = result.get("directories", [])
1133
+ ```
1134
+
1135
+ **Get directory details:**
1136
+ ```python
1137
+ result = api.session.rest_get(
1138
+ f"{BASE}/telephony/config/locations/{loc_id}/receptionistContacts/directories/{dir_id}"
1139
+ )
1140
+ ```
1141
+
1142
+ **Update directory (full replacement):**
1143
+ ```python
1144
+ body = {"name": "Updated Name", "contacts": [{"id": person_id_1}, {"id": person_id_2}]}
1145
+ api.session.rest_put(
1146
+ f"{BASE}/telephony/config/locations/{loc_id}/receptionistContacts/directories/{dir_id}",
1147
+ json=body
1148
+ )
1149
+ ```
1150
+
1151
+ **Delete directory:**
1152
+ ```python
1153
+ api.session.rest_delete(
1154
+ f"{BASE}/telephony/config/locations/{loc_id}/receptionistContacts/directories/{dir_id}"
1155
+ )
1156
+ ```
1157
+
1158
+ #### CLI Examples — Receptionist Contact Directories
1159
+
1160
+ ```bash
1161
+ # List receptionist contact directories for a location
1162
+ wxcli location-settings list-directories Y2lzY29zcGFyazovL...
1163
+
1164
+ # Get details for a specific directory
1165
+ wxcli location-settings show-directories Y2lzY29zcGFyazovL... --json-body '...'
1166
+
1167
+ # Create a new receptionist contact directory
1168
+ wxcli location-settings create-directories Y2lzY29zcGFyazovL... \
1169
+ --json-body '{"name": "Front Desk Contacts", "contacts": [{"id": "PERSON_ID"}]}'
1170
+
1171
+ # Update a directory (full replacement of contacts)
1172
+ wxcli location-settings update-directories Y2lzY29zcGFyazovL... \
1173
+ --json-body '{"name": "Updated Name", "contacts": [{"id": "PERSON_ID_1"}, {"id": "PERSON_ID_2"}]}'
1174
+
1175
+ # Delete a receptionist contact directory
1176
+ wxcli location-settings delete Y2lzY29zcGFyazovL...
1177
+ ```
1178
+
1179
+ ---
1180
+
1181
+ ### Additional Location-Level APIs on TelephonyLocationApi
1182
+
1183
+ #### `phone_numbers`
1184
+
1185
+ List service and standard PSTN numbers available to be assigned as the location's main number.
1186
+
1187
+ ```python
1188
+ def phone_numbers(
1189
+ self,
1190
+ location_id: str,
1191
+ phone_number: List[str] = None,
1192
+ owner_name: str = None,
1193
+ org_id: str = None,
1194
+ **params
1195
+ ) -> Generator[AvailableNumber, None, None]
1196
+ ```
1197
+
1198
+ #### `webex_go_available_phone_numbers`
1199
+
1200
+ List standard numbers available for Webex Go assignment at a location.
1201
+
1202
+ ```python
1203
+ def webex_go_available_phone_numbers(
1204
+ self,
1205
+ location_id: str,
1206
+ phone_number: List[str] = None,
1207
+ org_id: str = None,
1208
+ **params
1209
+ ) -> Generator[AvailableNumber, None, None]
1210
+ ```
1211
+
1212
+ #### `charge_number_available_phone_numbers`
1213
+
1214
+ List non-toll-free, non-mobile numbers available as the location's charge number.
1215
+
1216
+ ```python
1217
+ def charge_number_available_phone_numbers(
1218
+ self,
1219
+ location_id: str,
1220
+ phone_number: List[str] = None,
1221
+ owner_name: str = None,
1222
+ org_id: str = None,
1223
+ **params
1224
+ ) -> Generator[AvailableNumber, None, None]
1225
+ ```
1226
+
1227
+ #### Receptionist Contact Directories
1228
+
1229
+ These methods manage named directories of users and location features (Auto Attendant, Call Queue, Hunt Group, Single Number Reach, Paging Group):
1230
+
1231
+ ```python
1232
+ def create_receptionist_contact_directory(location_id, name, contacts, org_id=None) -> str
1233
+ def list_receptionist_contact_directories(location_id, org_id=None) -> List[IdAndName]
1234
+ def receptionist_contact_directory_details(location_id, directory_id, ...) -> List[ContactDetails]
1235
+ def delete_receptionist_contact_directory(location_id, directory_id, org_id=None)
1236
+ def modify_receptionist_contact_directory(location_id, directory_id, name, contacts, org_id=None) -> str
1237
+ ```
1238
+
1239
+ Note: `modify` performs a **full replacement** of the contacts list (not incremental). The details API is supported for orgs with fewer than 2000 users or location-based calling features; orgs exceeding this threshold get error 25395.
1240
+
1241
+ ---
1242
+
1243
+ ## 2. Voicemail Policies
1244
+
1245
+ ### Location Voicemail Settings
1246
+
1247
+ **API path:** `api.telephony.location.voicemail`
1248
+
1249
+ **Source:** `wxc_sdk.telephony.location.vm`
1250
+
1251
+ Currently limited to enabling/disabling voicemail transcription at the location level.
1252
+
1253
+ #### `LocationVoiceMailSettings` Model
1254
+
1255
+ | Field | Type | Description |
1256
+ |-------|------|-------------|
1257
+ | `voicemail_transcription_enabled` | `bool` | Enable/disable voicemail transcription for the location |
1258
+
1259
+ #### `read`
1260
+
1261
+ ```python
1262
+ def read(
1263
+ self,
1264
+ location_id: str,
1265
+ org_id: str = None
1266
+ ) -> LocationVoiceMailSettings
1267
+ ```
1268
+
1269
+ **Scope:** `spark-admin:telephony_config_read`
1270
+
1271
+ #### `update`
1272
+
1273
+ ```python
1274
+ def update(
1275
+ self,
1276
+ location_id: str,
1277
+ settings: LocationVoiceMailSettings,
1278
+ org_id: str = None
1279
+ )
1280
+ ```
1281
+
1282
+ **Scope:** `spark-admin:telephony_config_write`
1283
+
1284
+ #### CLI Examples
1285
+
1286
+ ```bash
1287
+ # Read location voicemail settings
1288
+ wxcli location-voicemail show Y2lzY29zcGFyazovL...
1289
+
1290
+ # Enable voicemail transcription for a location
1291
+ wxcli location-voicemail update Y2lzY29zcGFyazovL... --voicemail-transcription-enabled
1292
+
1293
+ # Disable voicemail transcription
1294
+ wxcli location-voicemail update Y2lzY29zcGFyazovL... --no-voicemail-transcription-enabled
1295
+ ```
1296
+
1297
+ ---
1298
+
1299
+ ### Raw HTTP — Location Voicemail
1300
+ <!-- Updated by playbook session 2026-03-18 -->
1301
+
1302
+ **Read location voicemail settings:**
1303
+ ```python
1304
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/voicemail")
1305
+ # {"voicemailTranscriptionEnabled": bool}
1306
+ ```
1307
+
1308
+ **Update location voicemail:**
1309
+ ```python
1310
+ body = {"voicemailTranscriptionEnabled": True}
1311
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/voicemail", json=body)
1312
+ ```
1313
+
1314
+ ---
1315
+
1316
+ ### Organisation Voicemail Settings
1317
+
1318
+ **API path:** `api.telephony.organisation_voicemail`
1319
+
1320
+ **Source:** `wxc_sdk.telephony.organisation_vm`
1321
+
1322
+ **Base endpoint:** `telephony/config/voicemail/settings`
1323
+
1324
+ Controls org-wide voicemail message expiry and forwarding policies.
1325
+
1326
+ #### `OrganisationVoicemailSettings` Model
1327
+
1328
+ | Field | Type | Description |
1329
+ |-------|------|-------------|
1330
+ | `message_expiry_enabled` | `bool` | Enable deletion conditions for expired messages |
1331
+ | `number_of_days_for_message_expiry` | `int` | Days after which messages expire |
1332
+ | `strict_deletion_enabled` | `bool` | When enabled, both read and unread messages are deleted based on expiry. When disabled, unread messages are kept. |
1333
+ | `voice_message_forwarding_enabled` | `bool` | Allow people to configure email forwarding of voicemails |
1334
+
1335
+ **Defaults** (from `OrganisationVoicemailSettings.default()`):
1336
+ ```python
1337
+ message_expiry_enabled = False
1338
+ number_of_days_for_message_expiry = 15
1339
+ strict_deletion_enabled = False
1340
+ voice_message_forwarding_enabled = False
1341
+ ```
1342
+
1343
+ #### `read`
1344
+
1345
+ ```python
1346
+ def read(
1347
+ self,
1348
+ org_id: str = None
1349
+ ) -> OrganisationVoicemailSettings
1350
+ ```
1351
+
1352
+ **Scope:** `spark-admin:telephony_config_read`
1353
+
1354
+ #### `update`
1355
+
1356
+ ```python
1357
+ def update(
1358
+ self,
1359
+ settings: OrganisationVoicemailSettings,
1360
+ org_id: str = None
1361
+ )
1362
+ ```
1363
+
1364
+ **Scope:** `spark-admin:telephony_config_write`
1365
+
1366
+ ---
1367
+
1368
+ ### Raw HTTP — Organisation Voicemail
1369
+ <!-- Updated by playbook session 2026-03-18 -->
1370
+
1371
+ **Read org voicemail settings:**
1372
+ ```python
1373
+ result = api.session.rest_get(f"{BASE}/telephony/config/voicemail/settings")
1374
+ # {"messageExpiryEnabled", "numberOfDaysForMessageExpiry", "strictDeletionEnabled",
1375
+ # "voiceMessageForwardingEnabled"}
1376
+ ```
1377
+
1378
+ **Update org voicemail settings:**
1379
+ ```python
1380
+ body = {
1381
+ "messageExpiryEnabled": True,
1382
+ "numberOfDaysForMessageExpiry": 30,
1383
+ "strictDeletionEnabled": False,
1384
+ "voiceMessageForwardingEnabled": True
1385
+ }
1386
+ api.session.rest_put(f"{BASE}/telephony/config/voicemail/settings", json=body)
1387
+ ```
1388
+
1389
+ ---
1390
+
1391
+ ## 3. Voicemail Rules (Org-Level Passcode Policy)
1392
+
1393
+ **API path:** `api.telephony.voicemail_rules`
1394
+
1395
+ **Source:** `wxc_sdk.telephony.vm_rules`
1396
+
1397
+ **Base endpoint:** `telephony/config/voicemail/rules`
1398
+
1399
+ Defines org-wide default voicemail passcode requirements.
1400
+
1401
+ ### `VoiceMailRules` Model
1402
+
1403
+ | Field | Type | Description |
1404
+ |-------|------|-------------|
1405
+ | `default_voicemail_pin_rules` | `DefaultVoicemailPinRules` | Read-only rules (excluded from update payload) |
1406
+ | `default_voicemail_pin_enabled` | `bool` | Enable setting a default pin for new users (update only) |
1407
+ | `default_voicemail_pin` | `str` | The default pin value (update only) |
1408
+ | `expire_passcode` | `EnabledAndNumberOfDays` | Passcode expiry settings |
1409
+ | `change_passcode` | `EnabledAndNumberOfDays` | Minimum days before passcode can be changed |
1410
+ | `block_previous_passcodes` | `BlockPreviousPasscodes` | Block reuse of N previous passcodes |
1411
+
1412
+ ### `DefaultVoicemailPinRules` Model (read-only)
1413
+
1414
+ | Field | Type | Description |
1415
+ |-------|------|-------------|
1416
+ | `block_repeated_patterns_enabled` | `bool` | Block repeated patterns |
1417
+ | `block_repeated_digits` | `BlockRepeatedDigits` | Block repeated digit groups (enabled, max) |
1418
+ | `block_contiguous_sequences` | `BlockContiguousSequences` | Block ascending/descending sequences (enabled, ascending count, descending count) |
1419
+ | `length` | `PinLength` | Min/max passcode length |
1420
+ | `default_voicemail_pin_enabled` | `bool` | Whether default pin is enabled |
1421
+
1422
+ ### Supporting Models
1423
+
1424
+ #### `BlockRepeatedDigits`
1425
+
1426
+ | Field | Type | Range | Description |
1427
+ |-------|------|-------|-------------|
1428
+ | `enabled` | `bool` | | Block repeated digits |
1429
+ | `max` | `int` | 1-6 | Max repeated digits allowed |
1430
+
1431
+ #### `BlockContiguousSequences`
1432
+
1433
+ | Field | Type | Range | Description |
1434
+ |-------|------|-------|-------------|
1435
+ | `enabled` | `bool` | | Block sequential digits |
1436
+ | `number_of_ascending_digits` | `int` | 2-5 | Ascending sequence length to block |
1437
+ | `number_of_descending_digits` | `int` | 2-5 | Descending sequence length to block |
1438
+
1439
+ #### `PinLength`
1440
+
1441
+ | Field | Type | Range | Description |
1442
+ |-------|------|-------|-------------|
1443
+ | `min` | `int` | 2-15 | Minimum passcode length |
1444
+ | `max` | `int` | 3-30 | Maximum passcode length |
1445
+
1446
+ #### `BlockPreviousPasscodes`
1447
+
1448
+ | Field | Type | Range | Description |
1449
+ |-------|------|-------|-------------|
1450
+ | `enabled` | `bool` | | Block reuse of previous passcodes |
1451
+ | `number_of_passcodes` | `int` | 1-10 | How many previous passcodes to block |
1452
+
1453
+ #### `EnabledAndNumberOfDays`
1454
+
1455
+ | Field | Type | Description |
1456
+ |-------|------|-------------|
1457
+ | `enabled` | `bool` | Feature on/off |
1458
+ | `number_of_days` | `int` | Number of days for expiry/change window |
1459
+
1460
+ ### Defaults (from `VoiceMailRules.default()`)
1461
+
1462
+ ```python
1463
+ expire_passcode: enabled=True, number_of_days=180
1464
+ change_passcode: enabled=False, number_of_days=1
1465
+ block_previous_passcodes: enabled=True, number_of_passcodes=10
1466
+ # Pin rules defaults:
1467
+ block_repeated_patterns: True
1468
+ block_repeated_digits: max=3
1469
+ block_contiguous_sequences: ascending=3, descending=3
1470
+ pin_length: min=6, max=30
1471
+ default_voicemail_pin: disabled
1472
+ ```
1473
+
1474
+ ### Methods
1475
+
1476
+ #### `read`
1477
+
1478
+ ```python
1479
+ def read(
1480
+ self,
1481
+ org_id: str = None
1482
+ ) -> VoiceMailRules
1483
+ ```
1484
+
1485
+ **Scope:** `spark-admin:telephony_config_read`
1486
+
1487
+ #### `update`
1488
+
1489
+ ```python
1490
+ def update(
1491
+ self,
1492
+ settings: VoiceMailRules,
1493
+ org_id: str = None
1494
+ )
1495
+ ```
1496
+
1497
+ **Important:** The `default_voicemail_pin_rules` field is **excluded** from the update payload. To set a default pin, use `default_voicemail_pin_enabled` and `default_voicemail_pin` on the `VoiceMailRules` object directly. If you enable a default pin, communicate it to your users -- they must reset it before accessing voicemail.
1498
+
1499
+ **Scope:** `spark-admin:telephony_config_write`
1500
+
1501
+ ---
1502
+
1503
+ ### Raw HTTP — Voicemail Rules
1504
+ <!-- Updated by playbook session 2026-03-18 -->
1505
+
1506
+ **Read org voicemail passcode rules:**
1507
+ ```python
1508
+ result = api.session.rest_get(f"{BASE}/telephony/config/voicemail/rules")
1509
+ # {"defaultVoicemailPinRules": {...}, "expirePasscode": {...},
1510
+ # "changePasscode": {...}, "blockPreviousPasscodes": {...}}
1511
+ ```
1512
+
1513
+ **Update org voicemail rules:**
1514
+ ```python
1515
+ body = {
1516
+ "defaultVoicemailPinEnabled": True,
1517
+ "defaultVoicemailPin": "654321",
1518
+ "expirePasscode": {"enabled": True, "numberOfDays": 90},
1519
+ "changePasscode": {"enabled": False, "numberOfDays": 1},
1520
+ "blockPreviousPasscodes": {"enabled": True, "numberOfPasscodes": 5}
1521
+ }
1522
+ api.session.rest_put(f"{BASE}/telephony/config/voicemail/rules", json=body)
1523
+ ```
1524
+
1525
+ > **Gotcha:** The `defaultVoicemailPinRules` field is **read-only** and excluded from update payloads. Set default PINs via the top-level `defaultVoicemailPinEnabled` and `defaultVoicemailPin` fields instead.
1526
+
1527
+ ---
1528
+
1529
+ ## 4. Voice Messaging (User-Level)
1530
+
1531
+ **API path:** `api.telephony.voice_messaging`
1532
+
1533
+ **Source:** `wxc_sdk.telephony.voice_messaging`
1534
+
1535
+ **Base endpoint:** `telephony/voiceMessages`
1536
+
1537
+ User-scoped API (not admin). Handles voicemail message retrieval, deletion, and read/unread status. All GET operations require `spark:calls_read`; write operations require `spark:calls_write`.
1538
+
1539
+ ### Models
1540
+
1541
+ #### `MessageSummary`
1542
+
1543
+ | Field | Type | Description |
1544
+ |-------|------|-------------|
1545
+ | `new_messages` | `int` | Count of unread voicemail messages |
1546
+ | `old_messages` | `int` | Count of read voicemail messages |
1547
+ | `new_urgent_messages` | `int` | Count of unread urgent messages |
1548
+ | `old_urgent_messages` | `int` | Count of read urgent messages |
1549
+
1550
+ #### `VoiceMessageDetails`
1551
+
1552
+ | Field | Type | Description |
1553
+ |-------|------|-------------|
1554
+ | `id` | `str` | Message identifier |
1555
+ | `duration` | `int` | Duration in seconds (not present for FAX) |
1556
+ | `calling_party` | `VoiceMailPartyInformation` | Who left the message |
1557
+ | `urgent` | `bool` | Urgent flag |
1558
+ | `confidential` | `bool` | Confidential flag |
1559
+ | `read` | `bool` | Whether the message has been read |
1560
+ | `fax_page_count` | `int` | Page count (FAX only) |
1561
+ | `created` | `str` | Timestamp of message creation |
1562
+
1563
+ #### `VoiceMailPartyInformation`
1564
+
1565
+ | Field | Type | Description |
1566
+ |-------|------|-------------|
1567
+ | `name` | `str` | Caller name (absent if privacy enabled) |
1568
+ | `number` | `str` | Caller number — digits, URI, or E.164 (absent if privacy enabled) |
1569
+ | `person_id` | `str` | Person ID (absent if privacy enabled) |
1570
+ | `place_id` | `str` | Place ID (absent if privacy enabled) |
1571
+ | `privacy_enabled` | `bool` | Whether privacy is on |
1572
+
1573
+ ### Methods
1574
+
1575
+ #### `summary`
1576
+
1577
+ ```python
1578
+ def summary(self) -> MessageSummary
1579
+ ```
1580
+
1581
+ Get voicemail message counts. **Scope:** `spark:calls_read`
1582
+
1583
+ #### `list`
1584
+
1585
+ ```python
1586
+ def list(
1587
+ self,
1588
+ line_owner_id: str = None,
1589
+ **params
1590
+ ) -> Generator[VoiceMessageDetails, None, None]
1591
+ ```
1592
+
1593
+ List all voicemail messages. `line_owner_id` supports secondary lines on shared devices.
1594
+
1595
+ **Scope:** `spark:calls_read`
1596
+
1597
+ #### `delete`
1598
+
1599
+ ```python
1600
+ def delete(self, message_id: str)
1601
+ ```
1602
+
1603
+ Delete a specific voicemail message. **Scope:** `spark:calls_write`
1604
+
1605
+ #### `mark_as_read`
1606
+
1607
+ ```python
1608
+ def mark_as_read(
1609
+ self,
1610
+ message_id: str,
1611
+ line_owner_id: str = None
1612
+ )
1613
+ ```
1614
+
1615
+ Mark a specific message (or all messages if `message_id` semantics allow) as read. **Scope:** `spark:calls_write`
1616
+
1617
+ #### `mark_as_unread`
1618
+
1619
+ ```python
1620
+ def mark_as_unread(
1621
+ self,
1622
+ message_id: str,
1623
+ line_owner_id: str = None
1624
+ )
1625
+ ```
1626
+
1627
+ Mark a specific message (or all messages) as unread. **Scope:** `spark:calls_write`
1628
+
1629
+ ---
1630
+
1631
+ ### Raw HTTP — Voice Messaging
1632
+ <!-- Updated by playbook session 2026-03-18 -->
1633
+
1634
+ Voice messaging is user-scoped (not admin). Uses `spark:calls_read` and `spark:calls_write` scopes.
1635
+
1636
+ **Get voicemail summary:**
1637
+ ```python
1638
+ result = api.session.rest_get(f"{BASE}/telephony/voiceMessages/summary")
1639
+ # {"newMessages", "oldMessages", "newUrgentMessages", "oldUrgentMessages"}
1640
+ ```
1641
+
1642
+ **List voicemail messages:**
1643
+ ```python
1644
+ result = api.session.rest_get(f"{BASE}/telephony/voiceMessages", params={"max": 100})
1645
+ messages = result.get("items", [])
1646
+ ```
1647
+
1648
+ **Delete a voicemail message:**
1649
+ ```python
1650
+ api.session.rest_delete(f"{BASE}/telephony/voiceMessages/{message_id}")
1651
+ ```
1652
+
1653
+ **Mark as read / unread:**
1654
+ ```python
1655
+ api.session.rest_put(f"{BASE}/telephony/voiceMessages/{message_id}/markAsRead")
1656
+ api.session.rest_put(f"{BASE}/telephony/voiceMessages/{message_id}/markAsUnread")
1657
+ ```
1658
+
1659
+ ---
1660
+
1661
+ ## 5. Voice Portal
1662
+
1663
+ **API path:** `api.telephony.voiceportal`
1664
+
1665
+ **Source:** `wxc_sdk.telephony.voiceportal`
1666
+
1667
+ **Base endpoint:** `telephony/config/locations/{locationId}/voicePortal`
1668
+
1669
+ Voice portals provide an interactive voice response (IVR) system so administrators can manage auto attendant announcements. Each location has one voice portal.
1670
+
1671
+ ### `VoicePortalSettings` Model
1672
+
1673
+ | Field | Type | Description |
1674
+ |-------|------|-------------|
1675
+ | `portal_id` | `str` | Voice Portal ID (aliased from `id`) |
1676
+ | `name` | `str` | Voice Portal name |
1677
+ | `language` | `str` | Language for audio announcements (excluded from updates) |
1678
+ | `language_code` | `str` | Language code for voicemail group audio announcement |
1679
+ | `extension` | `str` | Extension of incoming call |
1680
+ | `phone_number` | `str` | Phone number of incoming call |
1681
+ | `first_name` | `str` | **Deprecated.** Use `direct_line_caller_id_name` and `dial_by_name` instead. |
1682
+ | `last_name` | `str` | **Deprecated.** Use `direct_line_caller_id_name` and `dial_by_name` instead. |
1683
+ | `direct_line_caller_id_name` | `DirectLineCallerIdName` | Caller ID name shown for this voice portal |
1684
+ | `dial_by_name` | `str` | Name used for dial-by-name functions |
1685
+
1686
+ ### `PasscodeRules` Model
1687
+
1688
+ Voice portal passcode rules (separate from the org-level voicemail rules).
1689
+
1690
+ | Field | Type | Description |
1691
+ |-------|------|-------------|
1692
+ | `expire_passcode` | `ExpirePasscode` | Passcode expiry (enabled, days) |
1693
+ | `failed_attempts` | `FailedAttempts` | Lock after N failed attempts (enabled, attempts) |
1694
+ | `block_previous_passcodes` | `BlockPreviousPasscodes` | Block reuse of previous passcodes |
1695
+ | `block_repeated_digits` | `BlockRepeatedDigits` | Block repeated digit groups |
1696
+ | `block_contiguous_sequences` | `BlockContiguousSequences` | Block sequential digits |
1697
+ | `length` | `PinLength` | Min/max passcode length |
1698
+ | `block_reversed_user_number_enabled` | `bool` | Block reversed phone number/extension as passcode |
1699
+ | `block_user_number_enabled` | `bool` | Block user phone number/extension as passcode |
1700
+ | `block_repeated_patterns_enabled` | `bool` | Block repeated patterns |
1701
+ | `block_reversed_old_passcode_enabled` | `bool` | Block reversed old passcode |
1702
+
1703
+ ### Methods
1704
+
1705
+ #### `read`
1706
+
1707
+ ```python
1708
+ def read(
1709
+ self,
1710
+ location_id: str,
1711
+ org_id: str = None
1712
+ ) -> VoicePortalSettings
1713
+ ```
1714
+
1715
+ **Scope:** `spark-admin:telephony_config_read`
1716
+
1717
+ #### `update`
1718
+
1719
+ ```python
1720
+ def update(
1721
+ self,
1722
+ location_id: str,
1723
+ settings: VoicePortalSettings,
1724
+ passcode: str = None,
1725
+ org_id: str = None
1726
+ )
1727
+ ```
1728
+
1729
+ Update voice portal settings. Pass `passcode` to change the portal passcode (SDK sends both `newPasscode` and `confirmPasscode` automatically). The `portal_id` and `language` fields are excluded from the update payload.
1730
+
1731
+ **Scope:** `spark-admin:telephony_config_write`
1732
+
1733
+ #### `available_phone_numbers`
1734
+
1735
+ ```python
1736
+ def available_phone_numbers(
1737
+ self,
1738
+ location_id: str,
1739
+ phone_number: list[str] = None,
1740
+ org_id: str = None,
1741
+ **params
1742
+ ) -> Generator[AvailableNumber, None, None]
1743
+ ```
1744
+
1745
+ List numbers available to be assigned as the voice portal's phone number.
1746
+
1747
+ **Scope:** `spark-admin:telephony_config_read`
1748
+
1749
+ #### `passcode_rules`
1750
+
1751
+ ```python
1752
+ def passcode_rules(
1753
+ self,
1754
+ location_id: str,
1755
+ org_id: str = None
1756
+ ) -> PasscodeRules
1757
+ ```
1758
+
1759
+ Retrieve the voice portal passcode rules for a location.
1760
+
1761
+ **Scope:** `spark-admin:telephony_config_read`
1762
+
1763
+ #### CLI Examples
1764
+
1765
+ ```bash
1766
+ # Read voice portal settings for a location
1767
+ wxcli location-voicemail show-voice-portal Y2lzY29zcGFyazovL...
1768
+
1769
+ # Update voice portal settings
1770
+ wxcli location-voicemail update-voice-portal Y2lzY29zcGFyazovL... \
1771
+ --name "Voice Portal" \
1772
+ --extension "9999" \
1773
+ --language-code "en_us" \
1774
+ --dial-by-name "Voice Portal"
1775
+
1776
+ # Read voice portal passcode rules
1777
+ wxcli location-voicemail show-passcode-rules Y2lzY29zcGFyazovL...
1778
+
1779
+ # List available phone numbers for voice portal
1780
+ wxcli location-voicemail list-available-numbers-voice-portal Y2lzY29zcGFyazovL...
1781
+ ```
1782
+
1783
+ ---
1784
+
1785
+ ### Raw HTTP — Voice Portal
1786
+ <!-- Updated by playbook session 2026-03-18 -->
1787
+
1788
+ **Read voice portal settings:**
1789
+ ```python
1790
+ result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/voicePortal")
1791
+ # {"id", "name", "languageCode", "extension", "phoneNumber", "firstName", "lastName",
1792
+ # "directLineCallerIdName", "dialByName"}
1793
+ ```
1794
+
1795
+ **Update voice portal:**
1796
+ ```python
1797
+ body = {
1798
+ "name": "Voice Portal",
1799
+ "extension": "9999",
1800
+ "languageCode": "en_us",
1801
+ "dialByName": "Voice Portal"
1802
+ }
1803
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/voicePortal", json=body)
1804
+ ```
1805
+
1806
+ > **Gotcha:** To change the portal passcode via raw HTTP, include `newPasscode` and `confirmPasscode` in the body (the SDK wraps this for you, but raw HTTP requires both fields).
1807
+
1808
+ **Read voice portal passcode rules:**
1809
+ ```python
1810
+ result = api.session.rest_get(
1811
+ f"{BASE}/telephony/config/locations/{loc_id}/voicePortal/passcodeRules"
1812
+ )
1813
+ ```
1814
+
1815
+ **Available phone numbers for voice portal:**
1816
+ ```python
1817
+ result = api.session.rest_get(
1818
+ f"{BASE}/telephony/config/locations/{loc_id}/voicePortal/availableNumbers",
1819
+ params={"max": 1000}
1820
+ )
1821
+ numbers = result.get("availableNumbers", [])
1822
+ ```
1823
+
1824
+ ### Raw HTTP — Voicemail Groups
1825
+ <!-- Updated by playbook session 2026-03-18 -->
1826
+
1827
+ Voicemail groups are location-scoped features for shared voicemail boxes.
1828
+
1829
+ **List voicemail groups:**
1830
+ ```python
1831
+ params = {"locationId": loc_id, "max": 1000}
1832
+ result = api.session.rest_get(f"{BASE}/telephony/config/voicemailGroups", params=params)
1833
+ groups = result.get("voicemailGroups", [])
1834
+ ```
1835
+
1836
+ **Get voicemail group details:**
1837
+ ```python
1838
+ result = api.session.rest_get(
1839
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vmg_id}"
1840
+ )
1841
+ ```
1842
+
1843
+ **Create voicemail group:**
1844
+ ```python
1845
+ body = {
1846
+ "name": "Sales VM Group",
1847
+ "extension": "2000",
1848
+ "passcode": "123456",
1849
+ "languageCode": "en_us"
1850
+ }
1851
+ result = api.session.rest_post(
1852
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups", json=body
1853
+ )
1854
+ new_id = result.get("id")
1855
+ ```
1856
+
1857
+ **Update voicemail group:**
1858
+ ```python
1859
+ body = {"name": "Updated Sales VM", "enabled": True, "greeting": "CUSTOM"}
1860
+ api.session.rest_put(
1861
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vmg_id}", json=body
1862
+ )
1863
+ ```
1864
+
1865
+ **Delete voicemail group:**
1866
+ ```python
1867
+ api.session.rest_delete(
1868
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vmg_id}"
1869
+ )
1870
+ ```
1871
+
1872
+ **Available phone numbers for voicemail groups:**
1873
+ ```python
1874
+ # Regular available numbers
1875
+ api.session.rest_get(
1876
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/availableNumbers",
1877
+ params={"max": 1000}
1878
+ )
1879
+ # Fax message available numbers
1880
+ api.session.rest_get(
1881
+ f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/faxMessage/availableNumbers",
1882
+ params={"max": 1000}
1883
+ )
1884
+ ```
1885
+
1886
+ #### CLI Examples — Voicemail Groups
1887
+
1888
+ ```bash
1889
+ # List voicemail groups for a location
1890
+ wxcli location-voicemail list --location-id Y2lzY29zcGFyazovL...
1891
+
1892
+ # Get voicemail group details
1893
+ wxcli location-voicemail show-voicemail-groups Y2lzY29zcGFyazovL...
1894
+
1895
+ # Create a voicemail group
1896
+ wxcli location-voicemail create Y2lzY29zcGFyazovL... \
1897
+ --name "Sales VM Group" \
1898
+ --extension "2000" \
1899
+ --passcode "123456" \
1900
+ --language-code "en_us"
1901
+
1902
+ # Update a voicemail group
1903
+ wxcli location-voicemail update-voicemail-groups Y2lzY29zcGFyazovL... \
1904
+ --json-body '{"name": "Updated Sales VM", "enabled": true}'
1905
+
1906
+ # Delete a voicemail group
1907
+ wxcli location-voicemail delete Y2lzY29zcGFyazovL...
1908
+
1909
+ # List available phone numbers for voicemail groups
1910
+ wxcli location-voicemail list-available-numbers-voicemail-groups Y2lzY29zcGFyazovL...
1911
+
1912
+ # List fax message available phone numbers
1913
+ wxcli location-voicemail list-available-numbers-fax-message Y2lzY29zcGFyazovL...
1914
+ ```
1915
+
1916
+ ---
1917
+
1918
+ ## API Access Path Summary
1919
+
1920
+ | Setting | SDK Access Path | Scope |
1921
+ |---------|----------------|-------|
1922
+ | Location telephony details | `api.telephony.location.details()` | read |
1923
+ | Location list | `api.telephony.location.list()` | read |
1924
+ | Enable calling | `api.telephony.location.enable_for_calling()` | write |
1925
+ | Update location | `api.telephony.location.update()` | write |
1926
+ | Internal dialing | `api.telephony.location.internal_dialing.read/update()` | read/write |
1927
+ | Call intercept | `api.telephony.location.intercept.read/configure()` | read/write |
1928
+ | Music on hold | `api.telephony.location.moh.read/update()` | read/write |
1929
+ | Location numbers | `api.telephony.location.number.add/remove/activate/manage_number_state()` | write |
1930
+ | Location voicemail | `api.telephony.location.voicemail.read/update()` | read/write |
1931
+ | ECBN | `api.telephony.location.read_ecbn/update_ecbn()` | read/write |
1932
+ | Call captions | `api.telephony.location.get_call_captions_settings/update_call_captions_settings()` | read/write |
1933
+ | Announcement language | `api.telephony.location.change_announcement_language()` | write |
1934
+ | Device settings | `api.telephony.location.device_settings()` | read |
1935
+ | Safe delete check | `api.telephony.location.safe_delete_check_before_disabling_calling_location()` | read |
1936
+ | Org voicemail settings | `api.telephony.organisation_voicemail.read/update()` | read/write |
1937
+ | Voicemail rules | `api.telephony.voicemail_rules.read/update()` | read/write |
1938
+ | Voice messaging (user) | `api.telephony.voice_messaging.summary/list/delete/mark_as_read/mark_as_unread()` | calls_read/write |
1939
+ | Voice portal | `api.telephony.voiceportal.read/update/passcode_rules/available_phone_numbers()` | read/write |
1940
+
1941
+ ---
1942
+
1943
+ ## Raw HTTP URL Pattern Summary
1944
+ <!-- Updated by playbook session 2026-03-18 -->
1945
+
1946
+ | Area | URL Pattern | Methods |
1947
+ |------|-------------|---------|
1948
+ | Location calling config | `telephony/config/locations` | GET (list), POST (enable) |
1949
+ | Location details | `telephony/config/locations/{locId}` | GET, PUT |
1950
+ | Internal dialing | `telephony/config/locations/{locId}/internalDialing` | GET, PUT |
1951
+ | Call intercept | `telephony/config/locations/{locId}/intercept` | GET, PUT |
1952
+ | Music on hold | `telephony/config/locations/{locId}/musicOnHold` | GET, PUT |
1953
+ | ECBN | `telephony/config/locations/{locId}/features/emergencyCallbackNumber` | GET, PUT |
1954
+ | Call captions | `telephony/config/locations/{locId}/callCaptions` | GET, PUT |
1955
+ | Announcement language | `telephony/config/locations/{locId}/actions/modifyAnnouncementLanguage/invoke` | POST |
1956
+ | Private network connect | `telephony/config/locations/{locId}/privateNetworkConnect` | GET, PUT |
1957
+ | Safe delete precheck | `telephony/config/locations/{locId}/actions/precheckForDeletion/invoke` | POST |
1958
+ | Validate extensions | `telephony/config/locations/{locId}/actions/validateExtensions/invoke` | POST |
1959
+ | Validate extensions (org) | `telephony/config/actions/validateExtensions/invoke` | POST |
1960
+ | Location voicemail | `telephony/config/locations/{locId}/voicemail` | GET, PUT |
1961
+ | Voice portal | `telephony/config/locations/{locId}/voicePortal` | GET, PUT |
1962
+ | Voice portal passcode rules | `telephony/config/locations/{locId}/voicePortal/passcodeRules` | GET |
1963
+ | Org voicemail settings | `telephony/config/voicemail/settings` | GET, PUT |
1964
+ | Org voicemail rules | `telephony/config/voicemail/rules` | GET, PUT |
1965
+ | Voicemail groups (list) | `telephony/config/voicemailGroups` | GET |
1966
+ | Voicemail groups (CRUD) | `telephony/config/locations/{locId}/voicemailGroups/{vmgId}` | GET, PUT, DELETE |
1967
+ | Voicemail groups (create) | `telephony/config/locations/{locId}/voicemailGroups` | POST |
1968
+ | Receptionist directories | `telephony/config/locations/{locId}/receptionistContacts/directories` | GET, POST |
1969
+ | Receptionist directory | `telephony/config/locations/{locId}/receptionistContacts/directories/{dirId}` | GET, PUT, DELETE |
1970
+ | Delete calling location job | `telephony/config/jobs/locations/deleteCallingLocation` | GET, POST |
1971
+ | Routing prefix jobs | `telephony/config/jobs/updateRoutingPrefix` | GET |
1972
+
1973
+ ## Raw HTTP Gotchas
1974
+ <!-- Updated by playbook session 2026-03-18 -->
1975
+
1976
+ 1. **Lowercase language codes** -- The API rejects `en_US`; use `en_us` instead. Applies to both `announcementLanguage` on location updates and `announcementLanguageCode` on the language change action.
1977
+ 2. **`announcementLanguage` returns None** -- Even when a language is set, the GET response may return `null` for this field. This is a known API quirk.
1978
+ 3. **Voice portal passcode requires two fields** -- When changing passcode via raw HTTP, you must send both `newPasscode` and `confirmPasscode`. The SDK handles this automatically but raw HTTP does not.
1979
+ 4. **Receptionist directory modify is full replacement** -- PUT on a directory replaces the entire contacts list. Always include the full desired contacts array.
1980
+ 5. **No auto-pagination** -- All list endpoints require manual `max` and `start` params. Set `max=1000` for maximum page size.
1981
+ 6. **Action endpoints use POST** -- `validateExtensions`, `modifyAnnouncementLanguage`, `precheckForDeletion`, job pause/resume all use POST, not GET or PUT.
1982
+
1983
+ ## CLI: `calling-service` (Org-Level Calling Service Settings)
1984
+
1985
+ The `calling-service` CLI group covers org-level voicemail settings, voicemail rules, music on hold configuration, large organization status, and call captions. These are org-wide settings, not per-location.
1986
+
1987
+ | Command | Description |
1988
+ |---------|-------------|
1989
+ | `calling-service list` | List announcement languages |
1990
+ | `calling-service show` | Get org voicemail settings |
1991
+ | `calling-service update` | Update org voicemail settings |
1992
+ | `calling-service show-rules` | Get org voicemail rules (passcode policy) |
1993
+ | `calling-service update-rules` | Update org voicemail rules |
1994
+ | `calling-service show-settings` | Get org music on hold configuration |
1995
+ | `calling-service update-settings` | Update org music on hold configuration |
1996
+ | `calling-service show-large-org-status` | Get large organization status |
1997
+ | `calling-service show-call-captions` | Get org call captions settings |
1998
+ | `calling-service update-call-captions` | Update org call captions settings |
1999
+
2000
+ ```bash
2001
+ # List available announcement languages
2002
+ wxcli calling-service list
2003
+
2004
+ # Get org-level voicemail settings
2005
+ wxcli calling-service show
2006
+
2007
+ # Enable voicemail message expiry after 30 days
2008
+ wxcli calling-service update --message-expiry-enabled --number-of-days-for-message-expiry 30
2009
+
2010
+ # Get org music on hold configuration
2011
+ wxcli calling-service show-settings
2012
+
2013
+ # Check if this org qualifies as a large organization
2014
+ wxcli calling-service show-large-org-status
2015
+
2016
+ # Get org call captions settings
2017
+ wxcli calling-service show-call-captions
2018
+
2019
+ # Enable org-level closed captions and transcripts
2020
+ wxcli calling-service update-call-captions --org-closed-captions-enabled --org-transcripts-enabled
2021
+ ```
2022
+
2023
+ ## CLI Groups
2024
+
2025
+ | CLI Group |
2026
+ |-----------|
2027
+ | `location-call-settings` |
2028
+ | `location-call-settings-voicemail` |
2029
+ | `calling-service` |
2030
+
2031
+ ---
2032
+
2033
+ ## See Also
2034
+
2035
+ - **[Person Call Settings — Handling](person-call-settings-handling.md)** — Per-user call forwarding overrides and call intercept settings that override location-level defaults
2036
+ - **[Person Call Settings — Media](person-call-settings-media.md)** — Per-user voicemail settings, music on hold overrides, and call intercept at the person level
2037
+ - **[Person Call Settings — Behavior](person-call-settings-behavior.md)** — Per-user ECBN settings that override the location ECBN default