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,1320 @@
1
+ # Call Features: Auto Attendants, Call Queues, and Hunt Groups
2
+
3
+ Reference for Webex Calling's three major call-routing features. Sourced from the `wxc_sdk` Python SDK.
4
+
5
+ ## Sources
6
+
7
+ - wxc_sdk v1.30.0
8
+ - OpenAPI spec: specs/webex-cloud-calling.json
9
+ - developer.webex.com Call Features APIs
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ 1. [Auto Attendants](#1-auto-attendants)
16
+ 2. [Call Queues](#2-call-queues)
17
+ 3. [Hunt Groups](#3-hunt-groups)
18
+ 4. [Shared Forwarding API](#4-shared-forwarding-api)
19
+ 5. [Common Data Models (HG/CQ Base)](#5-common-data-models-hgcq-base)
20
+ 6. [Required Scopes](#6-required-scopes)
21
+ 7. [Dependencies](#7-dependencies)
22
+
23
+ ---
24
+
25
+ ## 1. Auto Attendants
26
+
27
+ ### Overview
28
+
29
+ Auto attendants play customized prompts and provide callers with menu options for routing their calls. They support separate menus for business hours and after hours, each configurable with key-press actions (transfer, dial-by-name, extension dialing, repeat menu, exit, etc.).
30
+
31
+ Use an auto attendant when you need an IVR-style front door: "Press 1 for Sales, 2 for Support..."
32
+
33
+ **SDK access path:** `api.telephony.auto_attendant`
34
+
35
+ ### API Operations
36
+
37
+ | Operation | Method | Signature |
38
+ |-----------|--------|-----------|
39
+ | **List** | `list()` | `list(org_id=None, location_id=None, name=None, phone_number=None, **params) -> Generator[AutoAttendant]` |
40
+ | **Get by name** | `by_name()` | `by_name(name, location_id=None, org_id=None) -> Optional[AutoAttendant]` |
41
+ | **Get details** | `details()` | `details(location_id, auto_attendant_id, org_id=None) -> AutoAttendant` |
42
+ | **Create** | `create()` | `create(location_id, settings: AutoAttendant, org_id=None) -> str` (returns new ID) |
43
+ | **Update** | `update()` | `update(location_id, auto_attendant_id, settings: AutoAttendant, org_id=None) -> None` |
44
+ | **Delete** | `delete_auto_attendant()` | `delete_auto_attendant(location_id, auto_attendant_id, org_id=None) -> None` |
45
+
46
+ ### Key Data Models
47
+
48
+ #### `AutoAttendant`
49
+
50
+ | Field | Type | Required for Create | Notes |
51
+ |-------|------|:-------------------:|-------|
52
+ | `name` | `str` | Yes | Unique name |
53
+ | `phone_number` | `str` | One of phone_number/extension | |
54
+ | `extension` | `str` | One of phone_number/extension | |
55
+ | `business_schedule` | `str` | Yes | Name of business hours schedule |
56
+ | `holiday_schedule` | `str` | No | Name of holiday schedule |
57
+ | `business_hours_menu` | `AutoAttendantMenu` | Yes | Defaults to single key: 0 -> EXIT |
58
+ | `after_hours_menu` | `AutoAttendantMenu` | Yes | Defaults to single key: 0 -> EXIT |
59
+ | `extension_dialing` | `Dialing` | No | `ENTERPRISE` or `GROUP` (default: ENTERPRISE) |
60
+ | `name_dialing` | `Dialing` | No | `ENTERPRISE` or `GROUP` (default: ENTERPRISE) |
61
+ | `language_code` | `str` | No | |
62
+ | `time_zone` | `str` | No | |
63
+ | `alternate_numbers` | `list[AlternateNumber]` | No | Only in details(), up to 10 |
64
+ | `first_name` / `last_name` | `str` | No | **Deprecated** -- use `direct_line_caller_id_name` and `dial_by_name` instead |
65
+ | `direct_line_caller_id_name` | `DirectLineCallerIdName` | No | Not supported in FedRAMP. See [authentication.md → FedRAMP](authentication.md#webex-for-government-fedramp) for all FedRAMP restrictions. |
66
+ | `dial_by_name` | `str` | No | Not supported in FedRAMP. See [authentication.md → FedRAMP](authentication.md#webex-for-government-fedramp) for all FedRAMP restrictions. |
67
+
68
+ **Convenience constructor:**
69
+ ```python
70
+ AutoAttendant.create(name="Main Menu",
71
+ business_schedule="Business Hours",
72
+ extension="1000")
73
+ ```
74
+
75
+ #### `AutoAttendantMenu`
76
+
77
+ | Field | Type | Notes |
78
+ |-------|------|-------|
79
+ | `greeting` | `Greeting` | `DEFAULT` or `CUSTOM` |
80
+ | `extension_enabled` | `bool` | Allow extension dialing from this menu |
81
+ | `audio_announcement_file` | `AnnAudioFile` | Required when greeting is CUSTOM |
82
+ | `key_configurations` | `list[AutoAttendantKeyConfiguration]` | Key-to-action mappings |
83
+ | `call_treatment` | `CallTreatment` | What to do when caller gives no input |
84
+
85
+ #### `AutoAttendantKeyConfiguration`
86
+
87
+ | Field | Type | Notes |
88
+ |-------|------|-------|
89
+ | `key` | `MenuKey` | `0`-`9`, `*`, `#` |
90
+ | `action` | `AutoAttendantAction` | See enum below |
91
+ | `description` | `str` | Optional |
92
+ | `value` | `str` | Destination number/extension for transfer actions |
93
+
94
+ #### Enum: `AutoAttendantAction`
95
+
96
+ | Value | Description |
97
+ |-------|-------------|
98
+ | `TRANSFER_WITHOUT_PROMPT` | Transfer immediately |
99
+ | `TRANSFER_WITH_PROMPT` | Play prompt then transfer |
100
+ | `TRANSFER_TO_OPERATOR` | Transfer to operator |
101
+ | `NAME_DIALING` | Dial by name directory |
102
+ | `EXTENSION_DIALING` | Dial by extension |
103
+ | `REPEAT_MENU` | Replay the menu |
104
+ | `EXIT` | Disconnect |
105
+ | `TRANSFER_TO_MAILBOX` | Transfer to voicemail |
106
+ | `RETURN_TO_PREVIOUS_MENU` | Go back one menu level |
107
+ | `PLAY_ANNOUNCEMENT` | Play an announcement |
108
+
109
+ #### `CallTreatment` (no-input handling)
110
+
111
+ | Field | Type | Notes |
112
+ |-------|------|-------|
113
+ | `retry_attempt_for_no_input` | `CallTreatmentRetry` | `NO_REPEAT`, `ONE_TIME`, `TWO_TIMES`, `THREE_TIMES` |
114
+ | `no_input_timer` | `int` | Seconds to wait (1-60, default 10) |
115
+ | `action_to_be_performed` | `ActionToBePerformed` | What to do after retries exhausted |
116
+
117
+ #### `ActionToBePerformedAction` (post-retry actions)
118
+
119
+ `PLAY_MESSAGE_AND_DISCONNECT`, `TRANSFER_WITHOUT_PROMPT`, `TRANSFER_WITH_PROMPT`, `TRANSFER_TO_OPERATOR`, `TRANSFER_TO_MAILBOX`, `DISCONNECT`
120
+
121
+ ### Phone Number/Extension Assignment
122
+
123
+ - Must provide at least one of `phone_number` or `extension` at creation.
124
+ - Available numbers for assignment:
125
+ - `primary_available_phone_numbers(location_id, ...)` -- unassigned numbers at the location
126
+ - `alternate_available_phone_numbers(location_id, ...)` -- numbers for alternate number assignment
127
+ - `call_forward_available_phone_numbers(location_id, ...)` -- assigned numbers available for forwarding
128
+
129
+ ### Announcements
130
+
131
+ - `list_announcement_files(location_id, auto_attendant_id, org_id=None) -> list[AnnAudioFile]`
132
+ - `delete_announcement_file(location_id, auto_attendant_id, file_name, org_id=None)`
133
+ - **Upload is supported via the Announcement Repository API** (`POST /telephony/config/announcements` or `POST /telephony/config/locations/{locationId}/announcements` with multipart/form-data). See [location-calling-media.md](location-calling-media.md) section 1.
134
+
135
+ ### Forwarding
136
+
137
+ Auto attendants have a `forwarding` sub-API (instance of `ForwardingApi` with `FeatureSelector.auto_attendants`). See [Shared Forwarding API](#4-shared-forwarding-api).
138
+
139
+ ### Raw HTTP
140
+ <!-- Updated by playbook session 2026-03-18 -->
141
+
142
+ ```python
143
+ from wxc_sdk import WebexSimpleApi
144
+ api = WebexSimpleApi() # auth via WEBEX_ACCESS_TOKEN env var
145
+ BASE = "https://webexapis.com/v1"
146
+ ```
147
+
148
+ **List auto attendants:**
149
+ ```python
150
+ params = {"locationId": loc_id, "max": 1000}
151
+ result = api.session.rest_get(f"{BASE}/telephony/config/autoAttendants", params=params)
152
+ aas = result.get("autoAttendants", [])
153
+ # Each item: {"id", "name", "locationId", "locationName", "phoneNumber", "extension", "enabled", ...}
154
+ ```
155
+
156
+ **Get details:**
157
+ ```python
158
+ aa = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/autoAttendants/{aa_id}")
159
+ ```
160
+
161
+ **Create auto attendant:**
162
+ ```python
163
+ body = {
164
+ "name": "Main Menu",
165
+ "extension": "1000",
166
+ "businessSchedule": "Business Hours", # must reference existing schedule
167
+ "businessHoursMenu": {
168
+ "greeting": "DEFAULT",
169
+ "extensionEnabled": True,
170
+ "keyConfigurations": [{"key": "0", "action": "EXIT"}]
171
+ },
172
+ "afterHoursMenu": {
173
+ "greeting": "DEFAULT",
174
+ "extensionEnabled": True,
175
+ "keyConfigurations": [{"key": "0", "action": "EXIT"}]
176
+ }
177
+ }
178
+ result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/autoAttendants", json=body)
179
+ new_id = result.get("id")
180
+ ```
181
+
182
+ Required fields: `name`, `extension` (or `phoneNumber`), `businessSchedule`, `businessHoursMenu`, `afterHoursMenu`. Both menus need `greeting`, `extensionEnabled`, and at least one `keyConfigurations` entry.
183
+
184
+ **Update auto attendant:**
185
+ ```python
186
+ body = {"name": "Updated Menu Name"} # partial update — only changed fields
187
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/autoAttendants/{aa_id}", json=body)
188
+ ```
189
+
190
+ **Delete auto attendant:**
191
+ ```python
192
+ api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/autoAttendants/{aa_id}")
193
+ ```
194
+
195
+ **Get call forwarding settings:**
196
+ ```python
197
+ fwd = api.session.rest_get(
198
+ f"{BASE}/telephony/config/locations/{loc_id}/autoAttendants/{aa_id}/callForwarding"
199
+ )
200
+ ```
201
+
202
+ ### CLI Examples
203
+
204
+ ```bash
205
+ # List all auto attendants (org-wide)
206
+ wxcli auto-attendant list
207
+
208
+ # List auto attendants at a specific location
209
+ wxcli auto-attendant list --location-id Y2lzY29zcGFyazovL...
210
+
211
+ # Filter by name
212
+ wxcli auto-attendant list --name "Main Menu"
213
+
214
+ # Get details for a specific auto attendant (JSON output)
215
+ wxcli auto-attendant show Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID
216
+
217
+ # Create a minimal auto attendant (basic fields only)
218
+ wxcli auto-attendant create Y2lzY29zcGFyazovL_LOC_ID \
219
+ --name "Main Menu" \
220
+ --extension "1000" \
221
+ --business-schedule "Business Hours"
222
+
223
+ # Create with full menu configuration via --json-body
224
+ wxcli auto-attendant create Y2lzY29zcGFyazovL_LOC_ID --json-body '{
225
+ "name": "Main Menu",
226
+ "extension": "1000",
227
+ "businessSchedule": "Business Hours",
228
+ "businessHoursMenu": {
229
+ "greeting": "DEFAULT",
230
+ "extensionEnabled": true,
231
+ "keyConfigurations": [
232
+ {"key": "1", "action": "TRANSFER_WITHOUT_PROMPT", "value": "2000"},
233
+ {"key": "2", "action": "TRANSFER_WITHOUT_PROMPT", "value": "3000"},
234
+ {"key": "0", "action": "TRANSFER_TO_OPERATOR", "value": ""}
235
+ ]
236
+ },
237
+ "afterHoursMenu": {
238
+ "greeting": "DEFAULT",
239
+ "extensionEnabled": true,
240
+ "keyConfigurations": [{"key": "0", "action": "EXIT", "value": ""}]
241
+ }
242
+ }'
243
+
244
+ # Update basic fields (name, extension)
245
+ wxcli auto-attendant update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID \
246
+ --name "Updated Main Menu"
247
+
248
+ # Update menu configuration via --json-body (required for menu changes)
249
+ wxcli auto-attendant update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID --json-body '{
250
+ "businessHoursMenu": {
251
+ "greeting": "DEFAULT",
252
+ "extensionEnabled": true,
253
+ "keyConfigurations": [
254
+ {"key": "1", "action": "TRANSFER_WITHOUT_PROMPT", "value": "2000"},
255
+ {"key": "0", "action": "EXIT", "value": ""}
256
+ ]
257
+ }
258
+ }'
259
+
260
+ # Delete an auto attendant
261
+ wxcli auto-attendant delete Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID --force
262
+
263
+ # Get call forwarding settings
264
+ wxcli auto-attendant show-call-forwarding Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID
265
+
266
+ # List announcement files
267
+ wxcli auto-attendant list-announcements Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_AA_ID
268
+ ```
269
+
270
+ ---
271
+
272
+ ## 2. Call Queues
273
+
274
+ ### Overview
275
+
276
+ Call queues temporarily hold calls in the cloud when all assigned agents are unavailable. Queued calls route to agents when they become available. Each queue has a lead number (external phone number) and an internal extension.
277
+
278
+ Use a call queue when callers should wait on hold until an agent is free (support lines, order lines, etc.).
279
+
280
+ **SDK access path:** `api.telephony.callqueue`
281
+
282
+ ### API Operations
283
+
284
+ | Operation | Method | Signature |
285
+ |-----------|--------|-----------|
286
+ | **List** | `list()` | `list(location_id=None, name=None, phone_number=None, department_id=None, department_name=None, has_cx_essentials=None, org_id=None, **params) -> Generator[CallQueue]` |
287
+ | **Get by name** | `by_name()` | `by_name(name, location_id=None, has_cx_essentials=None, org_id=None) -> Optional[CallQueue]` |
288
+ | **Get details** | `details()` | `details(location_id, queue_id, has_cx_essentials=None, org_id=None) -> CallQueue` |
289
+ | **Create** | `create()` | `create(location_id, settings: CallQueue, has_cx_essentials=None, org_id=None) -> str` |
290
+ | **Update** | `update()` | `update(location_id, queue_id, update: CallQueue, org_id=None) -> None` |
291
+ | **Delete** | `delete_queue()` | `delete_queue(location_id, queue_id, org_id=None) -> None` |
292
+ | **Org-level settings** | `get_call_queue_settings()` | `get_call_queue_settings(org_id=None) -> CallQueueSettings` |
293
+ | **Update org settings** | `update_call_queue_settings()` | `update_call_queue_settings(settings: CallQueueSettings, org_id=None) -> None` |
294
+ | **Available agents** | `available_agents()` | `available_agents(location_id, name=None, phone_number=None, order=None, org_id=None) -> Generator[AvailableAgent]` |
295
+
296
+ ### Key Data Models
297
+
298
+ #### `CallQueue` (extends `HGandCQ`)
299
+
300
+ | Field | Type | Required for Create | Notes |
301
+ |-------|------|:-------------------:|-------|
302
+ | `name` | `str` | Yes | Unique name |
303
+ | `phone_number` | `str` | One of phone_number/extension | |
304
+ | `extension` | `str` | One of phone_number/extension | |
305
+ | `agents` | `list[Agent]` | Yes | People, workspaces, or virtual lines |
306
+ | `call_policies` | `CallQueueCallPolicies` | Yes | Routing type, policy, call bounce, distinctive ring |
307
+ | `queue_settings` | `QueueSettings` | Yes | Queue size, overflow, announcements |
308
+ | `enabled` | `bool` | No | |
309
+ | `language_code` | `str` | No | |
310
+ | `time_zone` | `str` | No | |
311
+ | `allow_call_waiting_for_agents_enabled` | `bool` | No | |
312
+ | `allow_agent_join_enabled` | `bool` | No | Let agents join/unjoin |
313
+ | `phone_number_for_outgoing_calls_enabled` | `bool` | No | Allow queue number for outbound caller ID |
314
+ | `department` | `IdAndName` | No | |
315
+ | `has_cx_essentials` | `bool` | No | Customer Assist (formerly CX Essentials) license flag |
316
+
317
+ **Convenience constructor:**
318
+ ```python
319
+ CallQueue.create(name="Support Queue",
320
+ agents=[Agent(agent_id=user.person_id) for user in members],
321
+ queue_size=10,
322
+ extension="2000")
323
+ ```
324
+
325
+ #### `CallQueueCallPolicies`
326
+
327
+ | Field | Type | Notes |
328
+ |-------|------|-------|
329
+ | `routing_type` | `CQRoutingType` | `PRIORITY_BASED` or `SKILL_BASED` |
330
+ | `policy` | `Policy` | See Policy enum below |
331
+ | `call_bounce` | `CallBounce` | No-answer behavior |
332
+ | `distinctive_ring` | `DistinctiveRing` | Optional ring pattern |
333
+
334
+ #### Enum: `Policy` (shared with Hunt Groups)
335
+
336
+ | Value | Max Agents | Description |
337
+ |-------|:----------:|-------------|
338
+ | `CIRCULAR` | 1,000 | Round-robin after last agent that took a call |
339
+ | `REGULAR` | 1,000 | Top-down, restart from top each time |
340
+ | `SIMULTANEOUS` | 50 | Ring all agents at once |
341
+ | `UNIFORM` | 1,000 | Longest-idle agent first |
342
+ | `WEIGHTED` | 100 | Percentage-based distribution (up to 100%) |
343
+
344
+ #### Enum: `CQRoutingType`
345
+
346
+ | Value | Description |
347
+ |-------|-------------|
348
+ | `PRIORITY_BASED` | Uses routing policy directly |
349
+ | `SKILL_BASED` | Routes by agent skill level; policy is tiebreaker when skill levels match |
350
+
351
+ #### `CallBounce`
352
+
353
+ | Field | Type | Default | Notes |
354
+ |-------|------|---------|-------|
355
+ | `enabled` (alias: `callBounceEnabled`) | `bool` | `True` | Bounce after max_rings |
356
+ | `max_rings` (alias: `callBounceMaxRings`) | `int` | `5` | |
357
+ | `agent_unavailable_enabled` | `bool` | `True` | Bounce if agent goes unavailable |
358
+ | `alert_agent_enabled` | `bool` | `True` | Alert agent for long-held calls |
359
+ | `alert_agent_max_seconds` | `int` | `30` | |
360
+ | `on_hold_enabled` | `bool` | `False` | Bounce calls on hold too long |
361
+ | `on_hold_max_seconds` | `int` | `60` | |
362
+
363
+ ### Overflow Settings
364
+
365
+ #### `OverflowSetting` (inside `QueueSettings.overflow`)
366
+
367
+ | Field | Type | Notes |
368
+ |-------|------|-------|
369
+ | `action` | `OverflowAction` | What happens when queue is full |
370
+ | `send_to_voicemail` | `bool` | Forward to voicemail of internal number |
371
+ | `transfer_number` | `str` | Destination when action is TRANSFER_TO_PHONE_NUMBER |
372
+ | `overflow_after_wait_enabled` | `bool` | Trigger overflow after wait time |
373
+ | `overflow_after_wait_time` | `int` | Seconds before overflow triggers (no agent available) |
374
+ | `play_overflow_greeting_enabled` | `bool` | Play audio before overflow action |
375
+ | `greeting` | `Greeting` | `DEFAULT` or `CUSTOM` |
376
+ | `audio_announcement_files` | `list[AnnAudioFile]` | 1-4 files for CUSTOM greeting |
377
+
378
+ #### Enum: `OverflowAction`
379
+
380
+ | Value | Description |
381
+ |-------|-------------|
382
+ | `PERFORM_BUSY_TREATMENT` | Caller hears fast-busy tone |
383
+ | `TRANSFER_TO_PHONE_NUMBER` | Transfer to specified number |
384
+ | `PLAY_RINGING_UNTIL_CALLER_HANGS_UP` | Caller hears ringing until disconnect |
385
+
386
+ ### Queue Settings and Announcements
387
+
388
+ `QueueSettings` contains the full queue behavior configuration:
389
+
390
+ | Field | Type | Notes |
391
+ |-------|------|-------|
392
+ | `queue_size` | `int` | Maximum calls in queue; overflow triggers when exceeded |
393
+ | `call_offer_tone_enabled` | `bool` | Play tone to callers when routed to agent |
394
+ | `reset_call_statistics_enabled` | `bool` | Reset stats on queue entry |
395
+ | `overflow` | `OverflowSetting` | See above |
396
+ | `welcome_message` | `WelcomeMessageSetting` | First message callers hear; can be mandatory |
397
+ | `wait_message` | `WaitMessageSetting` | Estimated wait time or position |
398
+ | `comfort_message` | `ComfortMessageSetting` | Periodic message (promotions, info) |
399
+ | `comfort_message_bypass` | `ComfortMessageBypass` | Short comfort for quickly-answered calls |
400
+ | `moh_message` | `MohMessageSetting` | Music on hold (normal + alternate source) |
401
+ | `whisper_message` | `AudioSource` | Plays to agent before connection (identifies queue) |
402
+
403
+ #### `WelcomeMessageSetting` (extends `AudioSource`)
404
+
405
+ - `enabled`, `greeting` (`DEFAULT`/`CUSTOM`), `audio_announcement_files`
406
+ - `always_enabled`: If true, message plays even when agent is immediately available.
407
+
408
+ #### `WaitMessageSetting`
409
+
410
+ | Field | Type | Notes |
411
+ |-------|------|-------|
412
+ | `enabled` | `bool` | |
413
+ | `wait_mode` | `WaitMode` | `TIME` or `POSITION` |
414
+ | `handling_time` | `int` | Minutes for estimated wait (10-100) |
415
+ | `default_handling_time` | `int` | Default handling minutes (1-100) |
416
+ | `queue_position` | `int` | Position threshold (10-100) |
417
+ | `high_volume_message_enabled` | `bool` | |
418
+ | `estimated_waiting_time` | `int` | Seconds (10-600) |
419
+ | `callback_option_enabled` | `bool` | Default: false |
420
+ | `minimum_estimated_callback_time` | `int` | Minutes; default: 30 |
421
+ | `international_callback_enabled` | `bool` | Default: false |
422
+ | `play_updated_estimated_wait_message` | `bool` | |
423
+
424
+ #### `ComfortMessageSetting`
425
+
426
+ - `enabled`, `greeting`, `audio_announcement_files`
427
+ - `time_between_messages`: Interval in seconds (10-600, default 10)
428
+
429
+ #### `ComfortMessageBypass`
430
+
431
+ - `enabled`, `greeting`, `audio_announcement_files`
432
+ - `call_waiting_age_threshold`: Seconds (default 30)
433
+ - `play_announcement_after_ringing`: bool
434
+ - `ring_time_before_playing_announcement`: Seconds (default 10)
435
+
436
+ #### `MohMessageSetting`
437
+
438
+ - `normal_source`: `AudioSource` -- primary music on hold
439
+ - `alternate_source`: `AudioSource` -- alternate music on hold
440
+
441
+ ### Agent/Member Management
442
+
443
+ Agents can be people, workspaces, or virtual lines. The `Agent` model (from `hg_and_cq`):
444
+
445
+ | Field | Type | Notes |
446
+ |-------|------|-------|
447
+ | `agent_id` (alias: `id`) | `str` | Person/workspace/virtual line ID |
448
+ | `weight` | `str` | Only for WEIGHTED policy |
449
+ | `skill_level` | `int` | Only for SKILL_BASED routing |
450
+ | `join_enabled` | `bool` | Only for call queues -- agent's join status |
451
+
452
+ **Agents sub-API** (`api.telephony.callqueue.agents`):
453
+
454
+ | Method | Signature | Notes |
455
+ |--------|-----------|-------|
456
+ | `list()` | `list(location_id=None, queue_id=None, name=None, phone_number=None, join_enabled=None, has_cx_essentials=None, order=None, org_id=None) -> Generator[CallQueueAgent]` | List all agents across queues |
457
+ | `details()` | `details(id, has_cx_essentials=None, max_=50, start=0, org_id=None) -> CallQueueAgentDetail` | Get agent detail with their queue assignments |
458
+ | `update_call_queue_settings()` | `update_call_queue_settings(id, settings: list[AgentCallQueueSetting], has_cx_essentials=None, org_id=None)` | Update an agent's join status across multiple queues |
459
+
460
+ **Known SDK note:** The decoded value of the agent's `id` and the `type` returned are always `PEOPLE`, even for workspaces or virtual lines. This is a known platform issue that persists as of 2026-03-19. The OpenAPI spec defines `MemberType` as `["PEOPLE", "PLACE"]` and `GetPersonPlaceVirtualLineCallQueueObject.type` as `["PEOPLE", "PLACE", "VIRTUAL_LINE"]`, but the live API returns `"type": "PEOPLE"` for all agent types in queue detail responses. The `availableUsers` endpoint correctly returns `PLACE` and `VIRTUAL_LINE` types, but once assigned to a queue the type collapses to `PEOPLE`.
461
+
462
+ **Adding/removing agents from a queue** (from examples):
463
+ ```python
464
+ # Add agents
465
+ details = api.telephony.callqueue.details(location_id=loc_id, queue_id=q_id)
466
+ details.agents.append(Agent(agent_id=person.person_id))
467
+ update = CallQueue(agents=details.agents)
468
+ api.telephony.callqueue.update(location_id=loc_id, queue_id=q_id, update=update)
469
+
470
+ # Remove agents
471
+ details.agents = [a for a in details.agents if a.agent_id != target_id]
472
+ update = CallQueue(agents=details.agents)
473
+ api.telephony.callqueue.update(location_id=loc_id, queue_id=q_id, update=update)
474
+
475
+ # Toggle join/unjoin
476
+ for agent in details.agents:
477
+ agent.join_enabled = True # or False
478
+ update = CallQueue(agents=details.agents)
479
+ api.telephony.callqueue.update(location_id=loc_id, queue_id=q_id, update=update)
480
+ ```
481
+
482
+ ### Call Queue Policy Sub-API
483
+
484
+ **SDK access path:** `api.telephony.callqueue.policy`
485
+
486
+ These are additional routing policies that sit alongside the main queue configuration:
487
+
488
+ #### Holiday Service
489
+
490
+ | Method | Signature |
491
+ |--------|-----------|
492
+ | `holiday_service_details()` | `holiday_service_details(location_id, queue_id, org_id=None) -> HolidayService` |
493
+ | `holiday_service_update()` | `holiday_service_update(location_id, queue_id, update: HolidayService, org_id=None)` |
494
+
495
+ `HolidayService` fields:
496
+ - `holiday_service_enabled`: bool
497
+ - `action`: `CPActionType` -- `BUSY` or `TRANSFER`
498
+ - `holiday_schedule_name` / `holiday_schedule_level`: Which schedule to use (from `holiday_schedules` list)
499
+ - `transfer_phone_number`: Destination when action is TRANSFER
500
+ - `play_announcement_before_enabled`: bool
501
+ - `audio_message_selection`: `Greeting` (DEFAULT/CUSTOM)
502
+ - `audio_files`: `list[AnnAudioFile]`
503
+ - `holiday_schedules`: `list[CQHolidaySchedule]` -- read-only list of available schedules
504
+
505
+ #### Night Service
506
+
507
+ | Method | Signature |
508
+ |--------|-----------|
509
+ | `night_service_detail()` | `night_service_detail(location_id, queue_id, org_id=None) -> NightService` |
510
+ | `night_service_update()` | `night_service_update(location_id, queue_id, update: NightService, org_id=None)` |
511
+
512
+ `NightService` fields:
513
+ - `night_service_enabled`: bool
514
+ - `action`: `CPActionType` -- `BUSY` or `TRANSFER`
515
+ - `transfer_phone_number`: Destination when action is TRANSFER
516
+ - `announcement_mode`: `AnnouncementMode` -- `NORMAL` or `MANUAL`
517
+ - `business_hours_name` / `business_hours_level`: Schedule reference
518
+ - `force_night_service_enabled`: Override business hours
519
+ - Separate `audio_message_selection` / `audio_files` for NORMAL mode and `manual_audio_message_selection` / `manual_audio_files` for MANUAL mode
520
+
521
+ #### Stranded Calls
522
+
523
+ | Method | Signature |
524
+ |--------|-----------|
525
+ | `stranded_calls_details()` | `stranded_calls_details(location_id, queue_id, org_id=None) -> StrandedCalls` |
526
+ | `stranded_calls_update()` | `stranded_calls_update(location_id, queue_id, update: StrandedCalls, org_id=None)` |
527
+
528
+ Handles calls when all agents log off or become unavailable.
529
+
530
+ `StrandedCallsAction` enum:
531
+ | Value | Description |
532
+ |-------|-------------|
533
+ | `NONE` | Calls remain in queue |
534
+ | `BUSY` | Fast-busy tone |
535
+ | `TRANSFER` | Transfer to number |
536
+ | `NIGHT_SERVICE` | Use night service config |
537
+ | `RINGING` | Play ringback until caller hangs up |
538
+ | `ANNOUNCEMENT` | Play announcement in loop |
539
+
540
+ #### Forced Forward
541
+
542
+ | Method | Signature |
543
+ |--------|-----------|
544
+ | `forced_forward_details()` | `forced_forward_details(location_id, queue_id, org_id=None) -> ForcedForward` |
545
+ | `forced_forward_update()` | `forced_forward_update(location_id, queue_id, update: ForcedForward, org_id=None)` |
546
+
547
+ Temporarily diverts all incoming calls to a destination. Calls already in the queue remain queued.
548
+
549
+ `ForcedForward` fields:
550
+ - `forced_forward_enabled`: bool
551
+ - `transfer_phone_number`: Destination
552
+ - `play_announcement_before_enabled`: bool
553
+ - `audio_message_selection`: Greeting
554
+ - `audio_files`: list[AnnAudioFile]
555
+
556
+ ### Announcement Files Sub-API
557
+
558
+ **SDK access path:** `api.telephony.callqueue.announcement`
559
+
560
+ | Method | Signature |
561
+ |--------|-----------|
562
+ | `list()` | `list(location_id, queue_id, org_id=None) -> Generator[Announcement]` |
563
+ | `delete_announcement()` | `delete_announcement(location_id, queue_id, file_name, org_id=None)` |
564
+
565
+ `Announcement` model: `name` (alias: `fileName`), `size` (alias: `fileSize`)
566
+
567
+ **Upload is supported via the Announcement Repository API** (`POST /telephony/config/announcements` or `POST /telephony/config/locations/{locationId}/announcements` with multipart/form-data). See [location-calling-media.md](location-calling-media.md) section 1.
568
+
569
+ ### Phone Number/Extension Assignment
570
+
571
+ Same pattern as auto attendants:
572
+ - `primary_available_phone_numbers(location_id, ...)`
573
+ - `alternate_available_phone_numbers(location_id, ...)`
574
+ - `call_forward_available_phone_numbers(location_id, ...)`
575
+
576
+ ### Org-Level Call Queue Settings
577
+
578
+ `CallQueueSettings` (applies organization-wide):
579
+
580
+ | Field | Type | Notes |
581
+ |-------|------|-------|
582
+ | `maintain_queue_position_for_sim_ring_enabled` | `bool` | Optimized simultaneous ring algorithm |
583
+ | `force_agent_unavailable_on_bounced_enabled` | `bool` | Set agent unavailable on bounced calls |
584
+ | `play_tone_to_agent_for_barge_in_enabled` | `bool` | |
585
+ | `play_tone_to_agent_for_silent_monitoring_enabled` | `bool` | |
586
+ | `play_tone_to_agent_for_supervisor_coaching_enabled` | `bool` | |
587
+
588
+ ### Raw HTTP
589
+ <!-- Updated by playbook session 2026-03-18 -->
590
+
591
+ ```python
592
+ from wxc_sdk import WebexSimpleApi
593
+ api = WebexSimpleApi() # auth via WEBEX_ACCESS_TOKEN env var
594
+ BASE = "https://webexapis.com/v1"
595
+ ```
596
+
597
+ **List call queues:**
598
+ ```python
599
+ params = {"locationId": loc_id, "max": 1000}
600
+ result = api.session.rest_get(f"{BASE}/telephony/config/queues", params=params)
601
+ queues = result.get("queues", [])
602
+ # Each item: {"id", "name", "locationId", "locationName", "phoneNumber", "extension", "enabled", ...}
603
+ ```
604
+
605
+ **Get details:**
606
+ ```python
607
+ cq = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}")
608
+ ```
609
+
610
+ **Create call queue:**
611
+ ```python
612
+ body = {
613
+ "name": "Support Queue",
614
+ "extension": "2000",
615
+ "callPolicies": {
616
+ "routingType": "PRIORITY_BASED",
617
+ "policy": "CIRCULAR"
618
+ }
619
+ }
620
+ result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/queues", json=body)
621
+ new_id = result.get("id")
622
+ ```
623
+
624
+ Required fields: `name`, `extension` (or `phoneNumber`), `callPolicies` (with `routingType` and `policy`).
625
+
626
+ **Update call queue:**
627
+ ```python
628
+ body = {"name": "Updated Queue Name"} # partial update — only changed fields
629
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}", json=body)
630
+ ```
631
+
632
+ Gotcha: sending the full details object back on update fails with "Missing callingLineIdPhoneNumber" when `callingLineIdPolicy` is `CUSTOM`. Always use a partial object with only the fields you want to change.
633
+
634
+ **Delete call queue:**
635
+ ```python
636
+ api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}")
637
+ ```
638
+
639
+ **Add/remove agents via raw HTTP:**
640
+ ```python
641
+ # Get current details, modify agents, send partial update
642
+ cq = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}")
643
+ agents = cq.get("agents", [])
644
+ agents.append({"id": person_id})
645
+ api.session.rest_put(
646
+ f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}",
647
+ json={"agents": agents}
648
+ )
649
+ ```
650
+
651
+ **Call queue policy sub-APIs:**
652
+ ```python
653
+ # Holiday service
654
+ hs = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/holidayService")
655
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/holidayService", json=body)
656
+
657
+ # Night service
658
+ ns = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/nightService")
659
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/nightService", json=body)
660
+
661
+ # Stranded calls
662
+ sc = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/strandedCalls")
663
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/strandedCalls", json=body)
664
+
665
+ # Forced forward
666
+ ff = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/forcedForward")
667
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/forcedForward", json=body)
668
+ ```
669
+
670
+ **Call forwarding settings:**
671
+ ```python
672
+ fwd = api.session.rest_get(
673
+ f"{BASE}/telephony/config/locations/{loc_id}/queues/{queue_id}/callForwarding"
674
+ )
675
+ ```
676
+
677
+ ### CLI Examples
678
+
679
+ ```bash
680
+ # List all call queues (org-wide)
681
+ wxcli call-queue list
682
+
683
+ # List call queues at a specific location
684
+ wxcli call-queue list --location-id Y2lzY29zcGFyazovL...
685
+
686
+ # Filter by name
687
+ wxcli call-queue list --name "Support Queue"
688
+
689
+ # Get details for a specific call queue
690
+ wxcli call-queue show Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
691
+
692
+ # Create a basic call queue
693
+ wxcli call-queue create Y2lzY29zcGFyazovL_LOC_ID \
694
+ --name "Support Queue" \
695
+ --extension "2000"
696
+
697
+ # Create a call queue with agents and routing policy via --json-body
698
+ wxcli call-queue create Y2lzY29zcGFyazovL_LOC_ID --json-body '{
699
+ "name": "Support Queue",
700
+ "extension": "2000",
701
+ "callPolicies": {
702
+ "routingType": "PRIORITY_BASED",
703
+ "policy": "CIRCULAR"
704
+ },
705
+ "queueSettings": {
706
+ "queueSize": 15,
707
+ "overflow": {
708
+ "action": "PERFORM_BUSY_TREATMENT"
709
+ }
710
+ },
711
+ "agents": [
712
+ {"id": "PERSON_ID_1"},
713
+ {"id": "PERSON_ID_2"}
714
+ ]
715
+ }'
716
+
717
+ # Update basic fields
718
+ wxcli call-queue update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID \
719
+ --name "Renamed Queue" --enabled
720
+
721
+ # Update agents or complex settings via --json-body (partial update)
722
+ wxcli call-queue update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID --json-body '{
723
+ "agents": [
724
+ {"id": "PERSON_ID_1"},
725
+ {"id": "PERSON_ID_2"},
726
+ {"id": "PERSON_ID_3"}
727
+ ]
728
+ }'
729
+
730
+ # Delete a call queue
731
+ wxcli call-queue delete Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID --force
732
+
733
+ # List all call queue agents (org-wide or filtered)
734
+ wxcli call-queue list-agents
735
+ wxcli call-queue list-agents --queue-id Y2lzY29zcGFyazovL_QUEUE_ID
736
+
737
+ # Get call forwarding settings
738
+ wxcli call-queue show-call-forwarding Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
739
+
740
+ # View holiday service settings
741
+ wxcli call-queue list-holiday-service Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
742
+
743
+ # View night service, stranded calls, forced forward
744
+ wxcli call-queue list-night-service Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
745
+ wxcli call-queue list-stranded-calls Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
746
+ wxcli call-queue list-forced-forward Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_QUEUE_ID
747
+
748
+ # List available agents for a location
749
+ wxcli call-queue list-available-agents-queues --location-id Y2lzY29zcGFyazovL_LOC_ID
750
+ ```
751
+
752
+ ---
753
+
754
+ ## 3. Hunt Groups
755
+
756
+ ### Overview
757
+
758
+ Hunt groups route incoming calls to a group of people or workspaces using a configurable ring pattern. Unlike call queues, hunt groups do not hold calls in a queue -- they ring agents directly according to the routing policy, and if no one answers, the call follows no-answer/busy redirect rules.
759
+
760
+ Use a hunt group when calls should ring agents directly without queuing (small teams, on-call groups).
761
+
762
+ **SDK access path:** `api.telephony.huntgroup`
763
+
764
+ ### API Operations
765
+
766
+ | Operation | Method | Signature |
767
+ |-----------|--------|-----------|
768
+ | **List** | `list()` | `list(org_id=None, location_id=None, name=None, phone_number=None, **params) -> Generator[HuntGroup]` |
769
+ | **Get by name** | `by_name()` | `by_name(name, location_id=None, org_id=None) -> Optional[HuntGroup]` |
770
+ | **Get details** | `details()` | `details(location_id, huntgroup_id, org_id=None) -> HuntGroup` |
771
+ | **Create** | `create()` | `create(location_id, settings: HuntGroup, org_id=None) -> str` |
772
+ | **Update** | `update()` | `update(location_id, huntgroup_id, update: HuntGroup, org_id=None) -> None` |
773
+ | **Delete** | `delete_huntgroup()` | `delete_huntgroup(location_id, huntgroup_id, org_id=None) -> None` |
774
+
775
+ ### Key Data Models
776
+
777
+ #### `HuntGroup` (extends `HGandCQ`)
778
+
779
+ | Field | Type | Required for Create | Notes |
780
+ |-------|------|:-------------------:|-------|
781
+ | `name` | `str` | Yes | Unique name |
782
+ | `phone_number` | `str` | One of phone_number/extension | |
783
+ | `extension` | `str` | One of phone_number/extension | |
784
+ | `agents` | `list[Agent]` | No | Empty by default on creation |
785
+ | `call_policies` | `HGCallPolicies` | No | Auto-defaulted to CIRCULAR if not provided |
786
+ | `enabled` | `bool` | No | |
787
+ | `language_code` | `str` | No | |
788
+ | `time_zone` | `str` | No | |
789
+ | `alternate_numbers` | `list[AlternateNumber]` | No | Up to 10 |
790
+ | `hunt_group_caller_id_for_outgoing_calls_enabled` | `bool` | No | Use hunt group as outbound caller ID |
791
+
792
+ **Convenience constructor:**
793
+ ```python
794
+ HuntGroup.create(name="Sales Team",
795
+ extension="3000")
796
+ # Creates a minimal hunt group with no agents.
797
+ # call_policies defaults to CIRCULAR on API create().
798
+ ```
799
+
800
+ #### `HGCallPolicies`
801
+
802
+ | Field | Type | Default | Notes |
803
+ |-------|------|---------|-------|
804
+ | `policy` | `Policy` | `CIRCULAR` | Same Policy enum as call queues |
805
+ | `waiting_enabled` | `bool` | `False` | If false, acts as "advance when busy" -- skips agents on a call |
806
+ | `group_busy_enabled` | `bool` | No default | Set hunt group to busy status; all new calls get busy treatment |
807
+ | `allow_members_to_control_group_busy_enabled` | `bool` | No default | Let agents toggle group busy |
808
+ | `no_answer` | `NoAnswer` | See below | What happens when no agent answers |
809
+ | `busy_redirect` | `BusinessContinuity` | See below | Where to send calls when all agents busy or group is busy |
810
+ | `business_continuity_redirect` | `BusinessContinuity` | See below | Fallback when phone disconnected (power outage, etc.) |
811
+
812
+ #### `NoAnswer`
813
+
814
+ | Field | Type | Default | Notes |
815
+ |-------|------|---------|-------|
816
+ | `next_agent_enabled` | `bool` | `False` | Advance to next agent after rings |
817
+ | `next_agent_rings` | `int` | `5` | Rings before advancing |
818
+ | `forward_enabled` | `bool` | `False` | Forward unanswered calls |
819
+ | `destination` | `str` | None | Forward-to number |
820
+ | `number_of_rings` | `int` | `15` | Rings before forwarding |
821
+ | `system_max_number_of_rings` | `int` | `20` | Read-only system maximum |
822
+ | `destination_voicemail_enabled` | `bool` | `False` | Send to destination's voicemail (prefixes `*55`) |
823
+
824
+ #### `BusinessContinuity`
825
+
826
+ | Field | Type | Default | Notes |
827
+ |-------|------|---------|-------|
828
+ | `enabled` | `bool` | `False` | |
829
+ | `destination` | `str` | None | Redirect target |
830
+ | `destination_voicemail_enabled` | `bool` | `False` | |
831
+
832
+ ### Agent/Member Management
833
+
834
+ Hunt group agents use the same `Agent` model as call queues. To modify agents, update the hunt group with the new agent list:
835
+
836
+ ```python
837
+ hg = api.telephony.huntgroup.details(location_id=loc_id, huntgroup_id=hg_id)
838
+ hg.agents.append(Agent(agent_id=new_person_id))
839
+ api.telephony.huntgroup.update(location_id=loc_id, huntgroup_id=hg_id, update=hg)
840
+ ```
841
+
842
+ **Key difference from call queues:** Hunt groups do not have a `join_enabled` toggle on agents. All agents in the group receive calls (subject to the `waiting_enabled` setting).
843
+
844
+ ### Phone Number/Extension Assignment
845
+
846
+ - `primary_available_phone_numbers(location_id, ...)`
847
+ - `alternate_available_phone_numbers(location_id, ...)`
848
+ - `forward_available_phone_numbers(location_id, ...)` -- note the method name differs slightly from CQ/AA
849
+
850
+ ### Forwarding
851
+
852
+ Hunt groups have a `forwarding` sub-API (instance of `ForwardingApi` with `FeatureSelector.huntgroups`). See [Shared Forwarding API](#4-shared-forwarding-api).
853
+
854
+ ### Raw HTTP
855
+ <!-- Updated by playbook session 2026-03-18 -->
856
+
857
+ ```python
858
+ from wxc_sdk import WebexSimpleApi
859
+ api = WebexSimpleApi() # auth via WEBEX_ACCESS_TOKEN env var
860
+ BASE = "https://webexapis.com/v1"
861
+ ```
862
+
863
+ **List hunt groups:**
864
+ ```python
865
+ params = {"locationId": loc_id, "max": 1000}
866
+ result = api.session.rest_get(f"{BASE}/telephony/config/huntGroups", params=params)
867
+ hgs = result.get("huntGroups", [])
868
+ # Each item: {"id", "name", "locationId", "locationName", "phoneNumber", "extension", "enabled", ...}
869
+ ```
870
+
871
+ **Get details:**
872
+ ```python
873
+ hg = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}")
874
+ ```
875
+
876
+ **Create hunt group:**
877
+ ```python
878
+ body = {
879
+ "name": "Sales Team",
880
+ "extension": "3000"
881
+ }
882
+ result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/huntGroups", json=body)
883
+ new_id = result.get("id")
884
+ ```
885
+
886
+ Required fields: `name`, `extension` (or `phoneNumber`). `callPolicies` defaults to `CIRCULAR` if not provided. Agents are optional at creation -- can be added later via update.
887
+
888
+ **Update hunt group:**
889
+ ```python
890
+ body = {"name": "Updated Team Name"} # partial update — only changed fields
891
+ api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}", json=body)
892
+ ```
893
+
894
+ **Delete hunt group:**
895
+ ```python
896
+ api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}")
897
+ ```
898
+
899
+ **Add/remove agents via raw HTTP:**
900
+ ```python
901
+ hg = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}")
902
+ agents = hg.get("agents", [])
903
+ agents.append({"id": person_id})
904
+ api.session.rest_put(
905
+ f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}",
906
+ json={"agents": agents}
907
+ )
908
+ ```
909
+
910
+ **Call forwarding settings:**
911
+ ```python
912
+ fwd = api.session.rest_get(
913
+ f"{BASE}/telephony/config/locations/{loc_id}/huntGroups/{hg_id}/callForwarding"
914
+ )
915
+ ```
916
+
917
+ ### CLI Examples
918
+
919
+ ```bash
920
+ # List all hunt groups (org-wide)
921
+ wxcli hunt-group list
922
+
923
+ # List hunt groups at a specific location
924
+ wxcli hunt-group list --location-id Y2lzY29zcGFyazovL...
925
+
926
+ # Filter by name
927
+ wxcli hunt-group list --name "Sales Team"
928
+
929
+ # Get details for a specific hunt group
930
+ wxcli hunt-group show Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID
931
+
932
+ # Create a basic hunt group
933
+ wxcli hunt-group create Y2lzY29zcGFyazovL_LOC_ID \
934
+ --name "Sales Team" \
935
+ --extension "3000" \
936
+ --enabled
937
+
938
+ # Create with agents and call policies via --json-body
939
+ wxcli hunt-group create Y2lzY29zcGFyazovL_LOC_ID --json-body '{
940
+ "name": "Sales Team",
941
+ "extension": "3000",
942
+ "enabled": true,
943
+ "callPolicies": {
944
+ "policy": "SIMULTANEOUS",
945
+ "noAnswer": {
946
+ "nextAgentEnabled": true,
947
+ "nextAgentRings": 3,
948
+ "forwardEnabled": true,
949
+ "destination": "+15551234567",
950
+ "numberOfRings": 10
951
+ }
952
+ },
953
+ "agents": [
954
+ {"id": "PERSON_ID_1"},
955
+ {"id": "PERSON_ID_2"}
956
+ ]
957
+ }'
958
+
959
+ # Update basic fields
960
+ wxcli hunt-group update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID \
961
+ --name "Renamed Team" --enabled
962
+
963
+ # Update agents via --json-body (partial update)
964
+ wxcli hunt-group update Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID --json-body '{
965
+ "agents": [
966
+ {"id": "PERSON_ID_1"},
967
+ {"id": "PERSON_ID_2"},
968
+ {"id": "PERSON_ID_3"}
969
+ ]
970
+ }'
971
+
972
+ # Delete a hunt group
973
+ wxcli hunt-group delete Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID --force
974
+
975
+ # Get call forwarding settings
976
+ wxcli hunt-group show-call-forwarding Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID
977
+
978
+ # Create a selective call forwarding rule
979
+ wxcli hunt-group create-selective-rules Y2lzY29zcGFyazovL_LOC_ID Y2lzY29zcGFyazovL_HG_ID --json-body '{
980
+ "name": "After Hours Rule",
981
+ "enabled": true,
982
+ "businessSchedule": "Business Hours",
983
+ "forwardTo": {"selection": "FORWARD_TO_SPECIFIED_NUMBER", "phoneNumber": "+15559876543"},
984
+ "callsFrom": {"selection": "ANY"},
985
+ "callsTo": {"selection": "ANY"}
986
+ }'
987
+ ```
988
+
989
+ ---
990
+
991
+ ## 4. Shared Forwarding API
992
+
993
+ All three features (auto attendants, call queues, hunt groups) share the same `ForwardingApi` class, instantiated with a different `FeatureSelector`.
994
+
995
+ **SDK access paths:**
996
+ - `api.telephony.auto_attendant.forwarding`
997
+ - `api.telephony.callqueue.forwarding`
998
+ - `api.telephony.huntgroup.forwarding`
999
+
1000
+ ### API Endpoints
1001
+
1002
+ Base: `telephony/config/locations/{locationId}/{feature}/{featureId}/callForwarding`
1003
+
1004
+ | Method | Signature | Notes |
1005
+ |--------|-----------|-------|
1006
+ | `settings()` | `settings(location_id, feature_id, org_id=None) -> CallForwarding` | Get forwarding settings |
1007
+ | `update()` | `update(location_id, feature_id, forwarding: CallForwarding, org_id=None)` | Update forwarding settings |
1008
+ | `create_call_forwarding_rule()` | `create_call_forwarding_rule(location_id, feature_id, forwarding_rule: ForwardingRuleDetails, org_id=None) -> str` | Create selective rule; returns rule ID |
1009
+ | `call_forwarding_rule()` | `call_forwarding_rule(location_id, feature_id, rule_id, org_id=None) -> ForwardingRuleDetails` | Get rule details |
1010
+ | `update_call_forwarding_rule()` | `update_call_forwarding_rule(location_id, feature_id, rule_id, forwarding_rule: ForwardingRuleDetails, org_id=None) -> str` | Update rule; **rule ID changes if name changes** |
1011
+ | `delete_call_forwarding_rule()` | `delete_call_forwarding_rule(location_id, feature_id, rule_id, org_id=None)` | Delete a selective rule |
1012
+ | `switch_mode_for_call_forwarding()` | `switch_mode_for_call_forwarding(location_id, feature_id, org_id=None)` | Switch to normal operating mode |
1013
+
1014
+ ### Key Data Models
1015
+
1016
+ #### `CallForwarding`
1017
+
1018
+ | Field | Type | Notes |
1019
+ |-------|------|-------|
1020
+ | `always` | `ForwardingSetting` | Forward all calls unconditionally |
1021
+ | `selective` | `ForwardingSetting` | Forward based on rules |
1022
+ | `rules` | `list[ForwardingRule]` | Summary list of selective rules |
1023
+ | `operating_modes` | `ForwardOperatingModes` | Mode-based forwarding |
1024
+
1025
+ #### `ForwardingSetting`
1026
+
1027
+ | Field | Type | Notes |
1028
+ |-------|------|-------|
1029
+ | `enabled` | `bool` | |
1030
+ | `destination` | `str` | Forward-to number |
1031
+ | `ring_reminder_enabled` | `bool` | Brief tone on agent's phone |
1032
+ | `destination_voice_mail_enabled` | `bool` | Send to voicemail if destination is internal with VM |
1033
+
1034
+ #### `ForwardingRuleDetails`
1035
+
1036
+ | Field | Type | Notes |
1037
+ |-------|------|-------|
1038
+ | `name` | `str` | Rule name |
1039
+ | `id` | `str` | Rule ID (read-only, changes on name update) |
1040
+ | `enabled` | `bool` | |
1041
+ | `holiday_schedule` | `str` | Schedule name for holiday-based rules |
1042
+ | `business_schedule` | `str` | Schedule name for business-hours rules |
1043
+ | `forward_to` | `ForwardTo` | `FORWARD_TO_DEFAULT_NUMBER`, `FORWARD_TO_SPECIFIED_NUMBER`, or `DO_NOT_FORWARD` |
1044
+ | `calls_to` | `ForwardCallsTo` | Which incoming numbers trigger the rule |
1045
+ | `calls_from` | `CallsFrom` | `ANY` or `CUSTOM` with specific numbers |
1046
+
1047
+ ### Raw HTTP
1048
+ <!-- Updated by playbook session 2026-03-18 -->
1049
+
1050
+ The forwarding URL pattern is the same for all three features -- substitute the feature path segment:
1051
+
1052
+ | Feature | Path segment |
1053
+ |---------|-------------|
1054
+ | Auto Attendant | `autoAttendants` |
1055
+ | Call Queue | `queues` |
1056
+ | Hunt Group | `huntGroups` |
1057
+
1058
+ ```python
1059
+ BASE = "https://webexapis.com/v1"
1060
+ feature = "autoAttendants" # or "queues" or "huntGroups"
1061
+ feature_id = aa_id # or queue_id or hg_id
1062
+
1063
+ # Get forwarding settings
1064
+ fwd = api.session.rest_get(
1065
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding"
1066
+ )
1067
+
1068
+ # Update forwarding settings
1069
+ api.session.rest_put(
1070
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding",
1071
+ json={"always": {"enabled": True, "destination": "+15551234567"}}
1072
+ )
1073
+
1074
+ # Create selective forwarding rule
1075
+ rule_body = {
1076
+ "name": "After Hours Rule",
1077
+ "enabled": True,
1078
+ "businessSchedule": "Business Hours",
1079
+ "forwardTo": {"selection": "FORWARD_TO_SPECIFIED_NUMBER", "phoneNumber": "+15559876543"},
1080
+ "callsFrom": {"selection": "ANY"},
1081
+ "callsTo": {"selection": "ANY"}
1082
+ }
1083
+ result = api.session.rest_post(
1084
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding/selectiveRules",
1085
+ json=rule_body
1086
+ )
1087
+ rule_id = result.get("id")
1088
+
1089
+ # Get / update / delete a selective rule
1090
+ rule = api.session.rest_get(
1091
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding/selectiveRules/{rule_id}"
1092
+ )
1093
+ api.session.rest_put(
1094
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding/selectiveRules/{rule_id}",
1095
+ json={"enabled": False}
1096
+ )
1097
+ api.session.rest_delete(
1098
+ f"{BASE}/telephony/config/locations/{loc_id}/{feature}/{feature_id}/callForwarding/selectiveRules/{rule_id}"
1099
+ )
1100
+ ```
1101
+
1102
+ Gotcha: when you update a selective rule's `name`, the rule ID changes. The update response returns the new ID.
1103
+
1104
+ ### CLI Examples
1105
+
1106
+ The forwarding commands follow the same pattern across all three features. Substitute the feature command group (`auto-attendant`, `call-queue`, or `hunt-group`).
1107
+
1108
+ ```bash
1109
+ # Get call forwarding settings (same pattern for all three features)
1110
+ wxcli auto-attendant show-call-forwarding LOC_ID AA_ID
1111
+ wxcli call-queue show-call-forwarding LOC_ID QUEUE_ID
1112
+ wxcli hunt-group show-call-forwarding LOC_ID HG_ID
1113
+
1114
+ # Update call forwarding — enable always-forward via --json-body
1115
+ wxcli auto-attendant update-call-forwarding LOC_ID AA_ID --json-body '{
1116
+ "always": {"enabled": true, "destination": "+15551234567"}
1117
+ }'
1118
+
1119
+ wxcli call-queue update-call-forwarding LOC_ID QUEUE_ID --json-body '{
1120
+ "always": {"enabled": true, "destination": "+15551234567"}
1121
+ }'
1122
+
1123
+ wxcli hunt-group update-call-forwarding LOC_ID HG_ID --json-body '{
1124
+ "always": {"enabled": true, "destination": "+15551234567"}
1125
+ }'
1126
+
1127
+ # Create a selective forwarding rule
1128
+ wxcli auto-attendant create-selective-rules LOC_ID AA_ID \
1129
+ --name "After Hours Rule" --enabled --business-schedule "Business Hours"
1130
+
1131
+ # Create a selective rule with full config via --json-body
1132
+ wxcli call-queue create-selective-rules LOC_ID QUEUE_ID --json-body '{
1133
+ "name": "Holiday Redirect",
1134
+ "enabled": true,
1135
+ "holidaySchedule": "Company Holidays",
1136
+ "forwardTo": {"selection": "FORWARD_TO_SPECIFIED_NUMBER", "phoneNumber": "+15559876543"},
1137
+ "callsFrom": {"selection": "ANY"},
1138
+ "callsTo": {"selection": "ANY"}
1139
+ }'
1140
+
1141
+ # Get, update, and delete selective rules
1142
+ wxcli hunt-group show-selective-rules LOC_ID HG_ID RULE_ID
1143
+ wxcli hunt-group update-selective-rules LOC_ID HG_ID RULE_ID --json-body '{"enabled": false}'
1144
+ wxcli hunt-group delete-selective-rules LOC_ID HG_ID RULE_ID --force
1145
+
1146
+ # Switch to normal operating mode
1147
+ wxcli auto-attendant switch-mode-for LOC_ID AA_ID
1148
+ wxcli call-queue switch-mode-for LOC_ID QUEUE_ID
1149
+ wxcli hunt-group switch-mode-for LOC_ID HG_ID
1150
+ ```
1151
+
1152
+ ---
1153
+
1154
+ ## 5. Common Data Models (HG/CQ Base)
1155
+
1156
+ `HGandCQ` is the shared base class for both `CallQueue` and `HuntGroup`.
1157
+
1158
+ ### `HGandCQ` Fields
1159
+
1160
+ | Field | Type | Notes |
1161
+ |-------|------|-------|
1162
+ | `name` | `str` | |
1163
+ | `id` | `str` | Read-only |
1164
+ | `location_name` | `str` | Only from `list()` |
1165
+ | `location_id` | `str` | Only from `list()` |
1166
+ | `phone_number` | `str` | Primary number |
1167
+ | `extension` | `str` | |
1168
+ | `routing_prefix` | `str` | Location routing prefix |
1169
+ | `esn` | `str` | Routing prefix + extension |
1170
+ | `calling_line_id_policy` | `CallingLineIdPolicy` | `DIRECT_LINE`, `LOCATION_NUMBER`, or `CUSTOM` |
1171
+ | `calling_line_id_phone_number` | `str` | Shown when policy is CUSTOM |
1172
+ | `alternate_number_settings` | `AlternateNumberSettings` | Up to 10 alternate numbers with distinctive ring |
1173
+ | `enabled` | `bool` | |
1174
+ | `toll_free_number` | `bool` | Read-only |
1175
+ | `language` / `language_code` | `str` | |
1176
+ | `first_name` / `last_name` | `str` | Caller ID display names |
1177
+ | `time_zone` | `str` | |
1178
+ | `agents` | `list[Agent]` | |
1179
+ | `direct_line_caller_id_name` | `DirectLineCallerIdName` | |
1180
+ | `dial_by_name` | `str` | |
1181
+
1182
+ ### `AlternateNumberSettings`
1183
+
1184
+ | Field | Type | Notes |
1185
+ |-------|------|-------|
1186
+ | `distinctive_ring_enabled` | `bool` | Default: True |
1187
+ | `alternate_numbers` | `list[AlternateNumber]` | Up to 10 numbers |
1188
+
1189
+ ### `Agent`
1190
+
1191
+ | Field | Type | Notes |
1192
+ |-------|------|-------|
1193
+ | `agent_id` (alias: `id`) | `str` | Person, workspace, or virtual line ID |
1194
+ | `phone_number` | `str` | Read-only in responses |
1195
+ | `extension` | `str` | Read-only in responses |
1196
+ | `weight` | `str` | Only for WEIGHTED policy |
1197
+ | `skill_level` | `int` | Only for SKILL_BASED routing |
1198
+ | `join_enabled` | `bool` | Call queues only |
1199
+ | `location` | `IdAndName` | Read-only |
1200
+ | `has_cx_essentials` | `bool` | Read-only |
1201
+
1202
+ When creating/updating, only `agent_id` is required. Set `weight` or `skill_level` as needed for the routing policy.
1203
+
1204
+ ---
1205
+
1206
+ ## 6. Required Scopes
1207
+
1208
+ | Operation | Scope |
1209
+ |-----------|-------|
1210
+ | Read (list, details, settings) | `spark-admin:telephony_config_read` |
1211
+ | Write (create, update, delete) | `spark-admin:telephony_config_write` |
1212
+
1213
+ - **Full administrator** or **read-only administrator** tokens work for read operations.
1214
+ - **Full administrator** or **location administrator** tokens are required for write operations.
1215
+ - A **partner administrator** can use the `orgId` query parameter to manage customer organizations.
1216
+
1217
+ ---
1218
+
1219
+ ## 7. Dependencies
1220
+
1221
+ ### Prerequisites for All Three Features
1222
+
1223
+ 1. **Location must exist** -- all features are scoped to a location (`location_id` is required for create/details/update/delete).
1224
+ 2. **Phone number or extension** -- at least one must be provided at creation. Numbers must be unassigned and associated with the target location. Use the `primary_available_phone_numbers()` method to find candidates.
1225
+ 3. **Schedules** -- auto attendants require a `business_schedule` at creation. Call queue holiday/night service policies reference named schedules that must already exist at the org or location level.
1226
+
1227
+ ### Call Queue Specific
1228
+
1229
+ 4. **Agents** -- must be existing people, workspaces, or virtual lines. Users with Webex Calling Standard license are excluded from available agents.
1230
+ 5. **Queue size** -- must be specified either via `queue_size` parameter or a `QueueSettings` object.
1231
+ 6. **Customer Assist** -- if creating a Customer Assist (formerly CX Essentials) queue, agents must have the Customer Assist license.
1232
+
1233
+ ### Hunt Group Specific
1234
+
1235
+ 7. **Agents** -- same types as call queues (people, workspaces, virtual lines). A hunt group can be created with no agents and agents added later.
1236
+
1237
+ ### Auto Attendant Specific
1238
+
1239
+ 8. **Audio files** -- custom greetings require announcement audio files uploaded via the Announcement Repository API (`POST /telephony/config/announcements` with multipart/form-data). See [location-calling-media.md](location-calling-media.md) section 1 for upload details. WAV and WMA formats supported.
1240
+ 9. **FedRAMP** -- `directLineCallerIdName`, `customName`, and `dialByName` are not available in Webex for Government. Use `firstName`/`lastName` instead. See [authentication.md → FedRAMP](authentication.md#webex-for-government-fedramp) for all FedRAMP restrictions.
1241
+
1242
+ ### Auto Attendant API Gotchas
1243
+
1244
+ 10. **`wxcli auto-attendants update` only supports basic fields** -- the CLI `update` command accepts `--name`, `--extension`, `--phone-number`, `--enabled` only. Menu configuration (`businessHoursMenu`, `afterHoursMenu`) requires raw HTTP PUT to `telephony/config/locations/{locationId}/autoAttendants/{aaId}`.
1245
+
1246
+ 11. **`keyConfigurations.value` is mandatory in PUT** -- even for actions that don't use a destination (`TRANSFER_TO_OPERATOR`, `REPEAT_MENU`, `NAME_DIALING`, `EXTENSION_DIALING`), the `value` field must be present. Use `""` (empty string) for these actions. Omitting `value` or sending `null` causes error `25008 Missing Mandatory field name: HoursMenu.keyConfigurations.value`.
1247
+
1248
+ 12. **`TRANSFER_TO_MAILBOX` requires a non-empty `value`** -- empty string `""` is rejected. Use the target AA's own extension (e.g., `"8000"`) to route to the AA's own voicemail. This is the extension of the auto attendant whose mailbox should receive the call.
1249
+
1250
+ 13. **There is no `holidayMenu` field in the AA PUT body** -- the `holidayMenu` field is silently ignored by the API. The `afterHoursMenu` applies to both after-hours and holiday schedule periods. If you need different routing on holidays vs. after-hours, you need two separate auto attendants (one for after-hours, one for holidays).
1251
+
1252
+ 14. **After-hours phone numbers are normalized on read-back** -- a number sent as `+19195559876` returns as `+1-9195559876` in GET responses. Do not use the GET value as input to a subsequent PUT; use the original format.
1253
+
1254
+ ---
1255
+
1256
+ ## Appendix: Feature Comparison
1257
+
1258
+ | Capability | Auto Attendant | Call Queue | Hunt Group |
1259
+ |------------|:--------------:|:----------:|:----------:|
1260
+ | IVR menu with key-press routing | Yes | No | No |
1261
+ | Hold calls in queue | No | Yes | No |
1262
+ | Ring agents by policy | No | Yes | Yes |
1263
+ | Business/after-hours menus | Yes | Via policies | Via `waiting_enabled` / `no_answer` |
1264
+ | Holiday service | Via schedule | Yes (policy API) | Via forwarding rules (schedule-based) |
1265
+ | Night service | Via schedule | Yes (policy API) | Via forwarding rules (schedule-based) |
1266
+ | Stranded calls handling | N/A | Yes (policy API) | N/A |
1267
+ | Forced forward | N/A | Yes (policy API) | N/A |
1268
+ | Agent join/unjoin | N/A | Yes | No |
1269
+ | Agent skill-based routing | N/A | Yes | No |
1270
+ | Agent weight-based routing | N/A | Yes | Yes |
1271
+ | Whisper message to agent | N/A | Yes | No |
1272
+ | Comfort/wait messages | N/A | Yes | No |
1273
+ | Music on hold | N/A | Yes | No |
1274
+ | Max agents (simultaneous) | N/A | 50 | 50 |
1275
+ | Max agents (WEIGHTED) | N/A | 100 | 100 |
1276
+ | Max agents (CIRCULAR/REGULAR/UNIFORM) | N/A | 1,000 | 1,000 |
1277
+ | Shared forwarding API | Yes | Yes | Yes |
1278
+ | Announcement file management | Yes | Yes | No |
1279
+
1280
+ ---
1281
+
1282
+ ## Gotchas (Cross-Cutting)
1283
+
1284
+ 1. **Hunt groups ignore member personal call forwarding.** HG calls route directly to the agent's device and bypass any personal call forwarding the member has configured. Only the hunt group's own no-answer/forwarding settings govern overflow behavior.
1285
+
1286
+ 2. **DND on a hunt group member skips them, not their voicemail.** If a member has DND enabled, the hunt group skips that member and moves to the next — it does NOT send the call to the member's personal voicemail. The HG's no-answer action only triggers after all members are exhausted.
1287
+
1288
+ 3. **Partial updates are safer than full-object PUTs.** For all three features (AA, CQ, HG), sending the full GET response back as a PUT body can trigger validation errors on read-only or computed fields (e.g., `callingLineIdPolicy=CUSTOM` without a phone number on CQ). Always send only the fields you want to change.
1289
+
1290
+ 2. **`--json-body` is required for nested settings.** The CLI generator skips deeply nested object/array body fields. Menu configurations (AA), queue settings with announcements (CQ), and call policies with no-answer/bounce config (HG) all require `--json-body '{ ... }'` instead of individual flags.
1291
+
1292
+ 3. **Phone numbers normalize differently on read-back.** Numbers sent as `+19195559876` may return as `+1-9195559876` in GET responses. Do not round-trip GET values into PUT requests without stripping the dashes.
1293
+
1294
+ 4. **Agents share the same model but differ in behavior.** The `Agent` object is used by both CQ and HG, but `joinEnabled` only applies to call queues, and `skillLevel` only applies to `SKILL_BASED` routing in CQ. Sending these fields to the wrong feature is silently ignored.
1295
+
1296
+ 5. **Selective forwarding rule IDs change on name update.** Across all three features, renaming a selective forwarding rule changes its ID. The update response returns the new ID — capture it if you need to reference the rule again.
1297
+
1298
+ 6. **Audio file upload IS supported via API.** Use the Announcement Repository API (`POST /telephony/config/announcements` or `POST /telephony/config/locations/{locationId}/announcements`) with multipart/form-data encoding. Supports WAV and WMA formats. See [location-calling-media.md](location-calling-media.md) section 1 for full upload details and examples.
1299
+
1300
+ ---
1301
+
1302
+ ## See Also
1303
+
1304
+ - [Provisioning Reference](provisioning.md) -- creating locations and users (prerequisites for all features in this doc)
1305
+ - [Additional Call Features](call-features-additional.md) -- Paging Groups, Call Park, Call Pickup, Voicemail Groups, and Customer Assist (Call Park recall uses Hunt Groups; Voicemail Groups can serve as overflow destinations for CQ/HG)
1306
+ - [Call Routing & PSTN](call-routing.md) -- dial plans, trunks, and route lists (AA/CQ/HG phone numbers participate in the call routing chain)
1307
+ - [Location Call Settings: Media](location-calling-media.md) -- schedule management (business hours and holiday schedules used by AA menus and CQ/HG policies)
1308
+
1309
+ ## Migration Notes — CUCM Forwarding & Night Service
1310
+
1311
+ The CUCM-to-Webex migration pipeline writes hunt group and call queue forwarding via these per-feature endpoints:
1312
+
1313
+ - `PUT /telephony/config/locations/{locationId}/huntGroups/{huntGroupId}/callForwarding`
1314
+ - `PUT /telephony/config/locations/{locationId}/queues/{queueId}/callForwarding`
1315
+ - `PUT /telephony/config/locations/{locationId}/queues/{queueId}/holidayService`
1316
+ - `PUT /telephony/config/locations/{locationId}/queues/{queueId}/nightService`
1317
+ - `PUT /telephony/config/locations/{locationId}/queues/{queueId}/strandedCalls`
1318
+ - `PUT /telephony/config/locations/{locationId}/autoAttendants/{autoAttendantId}/callForwarding`
1319
+
1320
+ All endpoints require the same scope as feature creation (`spark-admin:telephony_config_write`). The migration tool only writes these settings when the corresponding CUCM source data is present; features without forwarding configuration are created with Webex defaults.