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,743 @@
1
+ <!-- Not directly verified via CLI — documents wxcadm library (not generated CLI commands) -->
2
+ <!-- wxcadm v4.6.1 review 2026-03-27: All v4.5.0–v4.6.1 changes verified present. WebexApi class, Org.api, Webex constructor simplification, WebexLicenseList/WebexLicense, parent→org renaming, Org.create_person removal, CPAPI auto-init commented out — all accurately documented. No discrepancies found. -->
3
+ # wxcadm Core Architecture
4
+
5
+ Reference for the core modules that form the foundation of wxcadm: entry point, organization management, API transport, data models, and exceptions.
6
+
7
+ Source: `wxcadm/__init__.py`, `wxcadm/webex.py`, `wxcadm/org.py`, `wxcadm/common.py`, `wxcadm/models.py`, `wxcadm/exceptions.py`
8
+
9
+ ---
10
+
11
+ <!-- Updated by playbook session 2026-03-18 -->
12
+ ## When to Use wxcadm vs Raw HTTP
13
+
14
+ | Use wxcadm when | Use raw HTTP when |
15
+ |---|---|
16
+ | You need **object model navigation** — traverse Org → Locations → People → Settings without knowing endpoint URLs | You need direct, targeted API calls to known endpoints |
17
+ | You want **lazy-loaded discovery** of all org resources (20+ collection properties auto-fetched on first access) | You want precise control over which API calls fire and when |
18
+ | You need **cross-org person lookups** via `Webex.get_person_by_email()` | You're doing standard CRUD on a single resource |
19
+ | You want the **XSI endpoint discovery** flow (`get_xsi_endpoints()`) for real-time event subscriptions | You want minimal dependencies and predictable latency |
20
+
21
+ > **Note:** The playbook uses raw HTTP via `api.session.rest_*()` for standard CRUD operations. wxcadm's core value is its object model — it discovers and caches org topology so you can navigate relationships without hardcoding endpoint paths. Use it for discovery and navigation, not as an API wrapper.
22
+
23
+ ---
24
+
25
+ ## Object Model Hierarchy
26
+
27
+ ```
28
+ Webex # Entry point. Holds token, orgs list.
29
+ +-- api: WebexApi # Session-based HTTP client (added v4.6.0)
30
+ +-- me: Me # Lazy-loaded identity of the token owner
31
+ +-- orgs: list[Org] # All orgs the token can manage
32
+ +-- org: Org # Default org (first, or selected by org_id)
33
+ +-- api: WebexApi # Org-scoped HTTP client (auto-adds orgId param)
34
+ +-- locations: LocationList
35
+ +-- people: PersonList
36
+ +-- devices: DeviceList
37
+ +-- call_queues: CallQueueList
38
+ +-- hunt_groups: HuntGroupList
39
+ +-- auto_attendants: AutoAttendantList
40
+ +-- workspaces: WorkspaceList
41
+ +-- virtual_lines: VirtualLineList
42
+ +-- numbers: NumberList
43
+ +-- licenses: WebexLicenseList
44
+ +-- announcements: AnnouncementList
45
+ +-- call_routing: CallRouting
46
+ +-- webhooks: Webhooks
47
+ +-- ... (20+ lazy-loaded collection properties)
48
+ ```
49
+
50
+ Nearly every collection property on `Org` is **lazy-loaded** -- the API call fires the first time the property is accessed, then the result is cached in a private `_attr`.
51
+
52
+ ---
53
+
54
+ ## Webex Class
55
+
56
+ **Module:** `wxcadm/webex.py`
57
+
58
+ The entry point. Authenticates with a Webex API access token, discovers orgs, and provides cross-org person lookups.
59
+
60
+ ### Constructor
61
+
62
+ ```python
63
+ wxcadm.Webex(
64
+ access_token: str,
65
+ fast_mode: bool = False,
66
+ client_id: Optional[str] = None,
67
+ client_secret: Optional[str] = None,
68
+ refresh_token: Optional[str] = None,
69
+ org_id: Optional[str] = None,
70
+ auto_refresh_token: bool = False,
71
+ read_only: bool = False,
72
+ ) -> Webex
73
+ ```
74
+
75
+ | Parameter | Purpose |
76
+ |-----------|---------|
77
+ | `access_token` | Webex API bearer token (required) |
78
+ | `fast_mode` | Skip per-person Call Control API calls on init. **Loses phone number data.** |
79
+ | `client_id` / `client_secret` / `refresh_token` | Needed only if you plan to call `get_new_token()` |
80
+ | `org_id` | Pin `self.org` to a specific org (UUID or full Webex ID accepted) |
81
+ | `auto_refresh_token` | Auto-refresh token when < 30 min from expiry. **Still in development -- do not use.** |
82
+ | `get_xsi` | If True, calls `get_xsi_endpoints()` on the default Org during init, populating `org.xsi` with XSI endpoint URLs. Equivalent to calling `webex.org.get_xsi_endpoints()` after init. See [wxcadm-xsi-realtime.md](wxcadm-xsi-realtime.md) for details. **Note:** This parameter appears in the `Webex.__init__` kwargs and is passed through to Org creation, but is not listed in the explicit constructor signature above -- it is handled via `**kwargs`. |
83
+ | `read_only` | If True, skips `GET /v1/organizations` (which needs admin scope) and discovers the org from `/v1/people/me` instead |
84
+
85
+ **Init behavior:**
86
+ 1. Creates a `WebexApi` instance at `self.api`.
87
+ 2. Sets the global `_webex_headers` dict (used by the legacy `webex_api_call()` function).
88
+ 3. If `read_only=False`: calls `GET /v1/organizations`, builds an `Org` for each, populates `self.orgs`.
89
+ 4. If `read_only=True`: calls `GET /v1/people/me`, extracts `orgId`, creates a single `Org`.
90
+ 5. Sets `self.org` to the first org, or to the org matching `org_id` if provided.
91
+
92
+ **Raises on init:**
93
+ - `TokenError` -- invalid/rejected access token (non-200 from `/v1/organizations`)
94
+ - `OrgError` -- no orgs returned, or `org_id` not found
95
+
96
+ ### Attributes
97
+
98
+ | Attribute | Type | Description |
99
+ |-----------|------|-------------|
100
+ | `orgs` | `list[Org]` | All orgs the token can manage |
101
+ | `org` | `Org` | Default org |
102
+ | `client_id` | `Optional[str]` | Integration/Service App client ID |
103
+ | `client_secret` | `Optional[str]` | Integration/Service App client secret |
104
+ | `refresh_token` | `Optional[str]` | Refresh token for token renewal |
105
+ | `access_token_expires` | `Optional[datetime]` | Set after `get_new_token()` |
106
+ | `refresh_token_expires` | `Optional[datetime]` | Set after `get_new_token()` |
107
+
108
+ ### Properties
109
+
110
+ ```python
111
+ @property
112
+ def headers(self) -> dict
113
+ ```
114
+ Returns the `{"Authorization": "Bearer ..."}` dict.
115
+
116
+ ```python
117
+ @property
118
+ def me(self) -> Me
119
+ ```
120
+ Lazy-loaded `Me` instance representing the token owner. Calls `GET /v1/people/me` on first access.
121
+
122
+ ### Methods
123
+
124
+ ```python
125
+ def get_new_token(
126
+ self,
127
+ client_id: Optional[str] = None,
128
+ client_secret: Optional[str] = None,
129
+ refresh_token: Optional[str] = None,
130
+ ) -> dict
131
+ ```
132
+ Refreshes the access token via `POST /v1/access_token`. Updates the instance and global headers in-place. Returns the token response dict. Raises `ValueError` if credentials are missing.
133
+
134
+ ```python
135
+ def get_org_by_name(self, name: str) -> Org
136
+ ```
137
+ Case-insensitive partial match on org name. Raises `KeyError` if not found.
138
+
139
+ ```python
140
+ def get_org_by_id(self, id: str) -> Org
141
+ ```
142
+ Matches against `org.id` or the decoded Spark ID. Raises `KeyError` if not found.
143
+
144
+ ```python
145
+ def get_person_by_email(self, email: str) -> Optional[Person]
146
+ ```
147
+ Cross-org lookup. Calls `GET /v1/people?email=...&callingData=True`. Returns `None` if no match. Raises `APIError` if Webex returns more than one record.
148
+
149
+ ```python
150
+ def get_person_by_id(self, id: str) -> Optional[Person]
151
+ ```
152
+ Cross-org lookup by Webex person ID. Same behavior as `get_person_by_email`.
153
+
154
+ ---
155
+
156
+ ## Org Class
157
+
158
+ **Module:** `wxcadm/org.py`
159
+
160
+ Represents a Webex Organization. Central hub for accessing all telephony resources.
161
+
162
+ ### Constructor
163
+
164
+ ```python
165
+ Org(
166
+ api_connection: Union[WebexApi, str],
167
+ name: str,
168
+ id: str,
169
+ parent: Webex = None,
170
+ xsi: bool = False,
171
+ **kwargs,
172
+ )
173
+ ```
174
+
175
+ Normally created by `Webex.__init__()`, not instantiated directly. Creates its own `WebexApi` instance scoped to this org (auto-injects `orgId` param on every request).
176
+
177
+ ### Lazy-Loaded Collection Properties
178
+
179
+ All are **cached after first access**. The API call happens on first read.
180
+
181
+ | Property | Return Type | Description |
182
+ |----------|-------------|-------------|
183
+ | `locations` | `LocationList` | All locations in the org |
184
+ | `people` | `PersonList` | All people (users) in the org |
185
+ | `devices` | `DeviceList` | All devices in the org |
186
+ | `numbers` | `NumberList` | All phone numbers in the org |
187
+ | `call_queues` | `CallQueueList` | All call queues |
188
+ | `hunt_groups` | `HuntGroupList` | All hunt groups |
189
+ | `auto_attendants` | `AutoAttendantList` | All auto attendants |
190
+ | `workspaces` | `WorkspaceList` | All workspaces |
191
+ | `virtual_lines` | `VirtualLineList` | All virtual lines |
192
+ | `licenses` | `WebexLicenseList` | All licenses in the org |
193
+ | `announcements` | `AnnouncementList` | All announcements |
194
+ | `playlists` | `PlaylistList` | All playlists |
195
+ | `voicemail_groups` | `VoicemailGroupList` | All voicemail groups |
196
+ | `dect_networks` | `DECTNetworkList` | All DECT networks |
197
+ | `paging_groups` | `list[PagingGroup]` | All paging groups |
198
+ | `supported_devices` | `SupportedDeviceList` | Supported device models |
199
+ | `translation_patterns` | `TranslationPatternList` | Translation patterns (org + location level) |
200
+ | `reports` | `ReportList` | All reports |
201
+ | `number_management_jobs` | `NumberManagementJobList` | Number management jobs |
202
+ | `user_move_jobs` | `UserMoveJobList` | User move jobs |
203
+ | `rebuild_phones_jobs` | `RebuildPhonesJobList` | Rebuild phones jobs |
204
+
205
+ ### Non-Cached Properties (re-fetched each access)
206
+
207
+ | Property | Return Type | Description |
208
+ |----------|-------------|-------------|
209
+ | `webhooks` | `Webhooks` | Webhooks for the org |
210
+ | `usergroups` | `UserGroups` | User groups |
211
+ | `applications` | `WebexApplications` | Service apps and integrations |
212
+ | `calls` | `Calls` | Active calls instance |
213
+ | `queue_settings` | `OrgQueueSettings` | Org-level queue settings |
214
+ | `compliance_announcement_settings` | `ComplianceAnnouncementSettings` | Call recording compliance settings |
215
+ | `recording_vendor` | `OrgRecordingVendorSelection` | Recording vendor config |
216
+
217
+ ### Computed Properties
218
+
219
+ ```python
220
+ @property
221
+ def spark_id(self) -> str
222
+ ```
223
+ Base64-decodes the Webex org ID to the Spark URI (e.g. `ciscospark://us/ORGANIZATION/...`).
224
+
225
+ ```python
226
+ @property
227
+ def org_id(self) -> str
228
+ ```
229
+ Alias for `self.id`. Convenience for API calls that need an `orgId` parameter.
230
+
231
+ ### Eagerly-Set Attributes
232
+
233
+ | Attribute | Type | Description |
234
+ |-----------|------|-------------|
235
+ | `name` | `str` | Organization display name |
236
+ | `id` | `str` | Webex organization ID |
237
+ | `xsi` | `dict` | XSI endpoint details (populated by `get_xsi_endpoints()`) |
238
+ | `call_routing` | `CallRouting` | Call routing instance (created in `__init__`) |
239
+ | `api` | `WebexApi` | Org-scoped API client |
240
+
241
+ ### Methods
242
+
243
+ #### Resource Lookup
244
+
245
+ ```python
246
+ def get_number_assignment(self, number: str) -> object | None
247
+ ```
248
+ Finds the owner (Person, Workspace, etc.) of a phone number. Uses partial match to handle E.164 vs. national format differences. Returns `None` if unassigned.
249
+
250
+ ```python
251
+ def get_paging_group(
252
+ self,
253
+ id: Optional[str] = None,
254
+ name: Optional[str] = None,
255
+ spark_id: Optional[str] = None,
256
+ ) -> Optional[PagingGroup]
257
+ ```
258
+ Search order: id, then name, then spark_id. Raises `ValueError` if called with no arguments.
259
+
260
+ ```python
261
+ def get_device_by_id(self, device_id: str) -> Device | False
262
+ ```
263
+ Finds a device by ID or decoded Spark ID. Returns `False` if not found.
264
+
265
+ ```python
266
+ def get_workspace_devices(self, workspace: Optional[Workspace] = None) -> list
267
+ ```
268
+ Without argument: returns list of Workspace instances with devices populated from number data. With argument: returns `workspace.devices`.
269
+
270
+ ```python
271
+ def get_all_monitoring(self) -> dict
272
+ ```
273
+ Returns a dict with keys `'people'`, `'workspaces'`, `'park_extensions'`, `'virtual_lines'`, each mapping monitored entity IDs to lists of monitoring Person/Workspace instances. Iterates all Webex Calling people and workspaces -- can be slow on large orgs.
274
+
275
+ #### License Helpers
276
+
277
+ ```python
278
+ def get_license_name(self, license_id: str) -> Optional[str]
279
+ ```
280
+ Returns license name by ID, or `None`.
281
+
282
+ #### XSI
283
+
284
+ ```python
285
+ def get_xsi_endpoints(self) -> Optional[dict]
286
+ ```
287
+ Calls `GET /v1/organizations/{id}?callingData=true` to populate `self.xsi` dict with keys: `xsi_domain`, `actions_endpoint`, `events_endpoint`, `events_channel_endpoint`. Returns `None` if XSI is not enabled.
288
+
289
+ #### Audit & Recordings
290
+
291
+ ```python
292
+ def get_audit_events(self, start: str, end: str) -> AuditEventList
293
+ ```
294
+ `start`/`end` format: `YYYY-MM-DD` or `YYYY-MM-DDTHH:MM:SS.000Z`. Auto-pads date-only strings.
295
+
296
+ ```python
297
+ def get_recordings(self, **kwargs) -> RecordingList
298
+ ```
299
+ kwargs passed through to `RecordingList`: `from_date_time` (str), `to_date_time` (str), `status` (str), `service` (str, maps to `serviceType`), `owner` (Person/Workspace/VirtualLine, uses `.id`), `region` (str, maps to `storageRegion`), `location` (Location, uses `.id`).
300
+
301
+ #### Admin Operations
302
+
303
+ ```python
304
+ def delete_person(self, person: Person) -> bool
305
+ ```
306
+ Calls `DELETE /v1/people/{id}`. Removes all licenses, numbers, and devices. Resets internal people cache.
307
+
308
+ #### Deprecated Methods
309
+
310
+ | Method | Replacement |
311
+ |--------|-------------|
312
+ | `get_person_by_id(id)` | `org.people.get(id=id)` |
313
+ | `get_person_by_email(email)` | `org.people.get(email=email)` |
314
+ | `get_hunt_group_by_id(id)` | `org.hunt_groups.get(id=id)` |
315
+ | `recorded_people` (property) | `org.people.recorded(True)` |
316
+ | `wxc_licenses` (property) | `org.licenses.webex_calling()` |
317
+ | `get_wxc_person_license()` | Use `org.licenses` / `WebexLicenseList` directly |
318
+ | `get_wxc_standard_license()` | Use `org.licenses` / `WebexLicenseList` directly |
319
+
320
+ ---
321
+
322
+ ## WebexLicenseList and WebexLicense
323
+
324
+ **Module:** `wxcadm/org.py`
325
+
326
+ ### WebexLicenseList
327
+
328
+ Extends `collections.UserList`. Fetches all licenses from `GET /v1/licenses` on init.
329
+
330
+ ```python
331
+ WebexLicenseList(org: Org)
332
+ ```
333
+
334
+ **Attributes:**
335
+ - `data: list[WebexLicense]` -- the license objects
336
+ - `assignable_subscriptions: list[str]` -- unique subscription IDs available for assignment
337
+
338
+ **Methods:**
339
+
340
+ ```python
341
+ def refresh(self) -> None
342
+ ```
343
+ Re-fetches license data from the API and updates counts.
344
+
345
+ ```python
346
+ def get(
347
+ self,
348
+ id: Optional[str] = None,
349
+ name: Optional[str] = None,
350
+ subscription: Optional[str] = None,
351
+ ) -> Optional[Union[WebexLicense, list[WebexLicense]]]
352
+ ```
353
+ Lookup by ID (exact), name (exact), or subscription (case-insensitive). Returns single match, list of matches, or `None`.
354
+
355
+ ```python
356
+ def webex_calling(
357
+ self,
358
+ type: str = 'all',
359
+ available_licenses_only: bool = False,
360
+ ) -> list[WebexLicense]
361
+ ```
362
+ Filter to Webex Calling licenses. `type` options: `'all'`, `'professional'`, `'workspace'`, `'hotdesk'`, `'standard'`.
363
+
364
+ ```python
365
+ def get_assignable_license(
366
+ self,
367
+ license_type: str,
368
+ ignore_license_overage: bool = False,
369
+ ) -> WebexLicense
370
+ ```
371
+ Finds an available license of the requested type from an assignable subscription. Raises `LicenseOverageError` or `NotSubscribedForLicenseError` as appropriate. `license_type` values: `'professional'`, `'workspace'`, `'standard'`, `'hotdesk'`.
372
+
373
+ ### WebexLicense
374
+
375
+ Represents a single license entry.
376
+
377
+ | Attribute | Type | Description |
378
+ |-----------|------|-------------|
379
+ | `name` | `str` | License name (e.g. "Webex Calling - Professional") |
380
+ | `id` | `str` | License ID |
381
+ | `total` | `int` | Total units in subscription |
382
+ | `consumed` | `int` | Consumed units |
383
+ | `consumed_by_users` | `int` | Units consumed by users |
384
+ | `consumed_by_workspaces` | `int` | Units consumed by workspaces |
385
+ | `subscription` | `Optional[str]` | Subscription ID |
386
+ | `wxc_license` | `bool` | True if this is a Webex Calling license |
387
+ | `wxc_type` | `Optional[str]` | `'professional'`, `'workspace'`, `'hotdesk'`, `'standard'`, or `None` |
388
+
389
+ Type detection is name-based: "Professional" -> `professional`, "Workspace" -> `workspace`, "Hot desk only" -> `hotdesk`, "Basic" -> `standard`.
390
+
391
+ ---
392
+
393
+ ## WebexApi Class
394
+
395
+ **Module:** `wxcadm/common.py`
396
+
397
+ Session-based HTTP client for the Webex API. Added in v4.6.0 to replace the standalone `webex_api_call()` function.
398
+
399
+ ### Constructor
400
+
401
+ ```python
402
+ WebexApi(
403
+ access_token: str,
404
+ org_id: Optional[str] = None,
405
+ url_base: str = "https://webexapis.com/",
406
+ retry_count: int = 10,
407
+ )
408
+ ```
409
+
410
+ When `org_id` is provided, every request automatically includes `orgId` as a query parameter.
411
+
412
+ Uses a persistent `requests.Session` with pre-configured headers:
413
+ ```
414
+ Authorization: Bearer {access_token}
415
+ Content-Type: application/json
416
+ Accept: application/json
417
+ ```
418
+
419
+ ### Methods
420
+
421
+ All methods handle:
422
+ - **429 Too Many Requests**: sleeps for `Retry-After` seconds, retries up to `retry_count` times
423
+ - **451 Unavailable For Legal Reasons**: cross-region redirect -- extracts new domain from error message and retries
424
+ - **Pagination**: follows `r.links['next']` until all pages are collected (GET only)
425
+
426
+ ```python
427
+ def get(
428
+ self,
429
+ endpoint: str,
430
+ params: Optional[dict] = None,
431
+ items_key: str = 'items',
432
+ kwargs: Optional[dict] = None,
433
+ ) -> Union[list, dict]
434
+ ```
435
+ Returns `response[items_key]` for list responses (with automatic pagination), or the full response dict for single-entity responses.
436
+
437
+ ```python
438
+ def put(self, endpoint: str, payload: Optional[dict] = None, params: Optional[dict] = None) -> Union[dict, bool]
439
+ ```
440
+
441
+ ```python
442
+ def post(self, endpoint: str, payload: Optional[dict] = None, params: Optional[dict] = None) -> Union[dict, bool]
443
+ ```
444
+
445
+ ```python
446
+ def delete(self, endpoint: str, params: Optional[dict] = None) -> Union[dict, bool]
447
+ ```
448
+
449
+ ```python
450
+ def patch(self, endpoint: str, payload: Optional[dict] = None, params: Optional[dict] = None) -> Union[dict, bool]
451
+ ```
452
+
453
+ ```python
454
+ def put_upload(self, endpoint: str, payload: MultipartEncoder = None, params: Optional[dict] = None) -> Union[dict, bool]
455
+ ```
456
+
457
+ ```python
458
+ def post_upload(self, endpoint: str, payload: MultipartEncoder = None, params: Optional[dict] = None) -> Union[dict, bool]
459
+ ```
460
+
461
+ For `put_upload` and `post_upload`, the payload must be a `requests_toolbelt.MultipartEncoder`. A separate session is created with `Content-Type` set to `payload.content_type`.
462
+
463
+ All mutating methods (PUT, POST, DELETE, PATCH) return:
464
+ - The parsed JSON response dict if the API returns a body
465
+ - `True` if the API returns success with no body
466
+ - `False` if retries are exhausted (429 scenario)
467
+
468
+ All raise `APIError` on non-retryable HTTP errors.
469
+
470
+ ### Two-Instance Pattern
471
+
472
+ `Webex.__init__` creates one `WebexApi` at `self.api` (no org scope). Each `Org.__init__` creates a second `WebexApi` scoped to that org. In practice you use `org.api` for most calls.
473
+
474
+ ---
475
+
476
+ ## Legacy webex_api_call() Function
477
+
478
+ **Module:** `wxcadm/common.py`
479
+
480
+ ```python
481
+ def webex_api_call(
482
+ method: str,
483
+ url: str,
484
+ headers: Optional[dict] = None,
485
+ params: Optional[dict] = None,
486
+ payload: dict | MultipartEncoder | None = None,
487
+ retry_count: Optional[int] = 5,
488
+ domain: Optional[str] = None,
489
+ **kwargs,
490
+ ) -> Union[list, dict, bool]
491
+ ```
492
+
493
+ Standalone function that predates `WebexApi`. Still in the codebase and used by some modules. Supports the same HTTP methods and retry logic as `WebexApi` but creates a new `requests.Session` per call instead of reusing one.
494
+
495
+ `method` values: `"get"`, `"post"`, `"put"`, `"put_upload"`, `"post_upload"`, `"delete"`, `"patch"`.
496
+
497
+ Uses the global `_webex_headers` dict (set during `Webex.__init__`) unless `headers` is explicitly provided.
498
+
499
+ **Prefer `WebexApi` methods over this function in new code.**
500
+
501
+ ---
502
+
503
+ ## Utility Functions
504
+
505
+ **Module:** `wxcadm/common.py`
506
+
507
+ ```python
508
+ def console_logging(level: str = "debug", formatter: Optional[logging.Formatter] = None) -> None
509
+ ```
510
+ Adds a STDOUT logging handler. `level` options: `"debug"`, `"info"`, `"warning"`, `"critical"`, `"none"` (removes handler). Default format: `%(levelname)s:\t%(message)s`.
511
+
512
+ ```python
513
+ def decode_spark_id(id: str) -> str
514
+ ```
515
+ Base64-decodes a Webex ID to its Spark URI. Example result: `ciscospark://us/PEOPLE/5b7ddefe-cc47-496a-8df0-18d8e4182a99`. Use `.split('/')[-1]` to extract just the UUID.
516
+
517
+ ```python
518
+ def tracking_id() -> str
519
+ ```
520
+ Generates a tracking ID string in the format `WXCADM_{uuid4}`.
521
+
522
+ ```python
523
+ def location_finder(location_id: str, parent) -> Optional[Location]
524
+ ```
525
+ Resolves a Location instance from either an Org or Location parent. Used internally.
526
+
527
+ ---
528
+
529
+ ## Data Models
530
+
531
+ **Module:** `wxcadm/models.py`
532
+
533
+ ### LocationEmergencySettings
534
+
535
+ ```python
536
+ class LocationEmergencySettings(NamedTuple):
537
+ integration: bool # Whether location data is being sent to RedSky
538
+ routing: bool # Whether 911 calls are being routed to RedSky
539
+ ```
540
+
541
+ ### OutboundProxy
542
+
543
+ Dataclass with `dataclass_json` serialization. Represents SIP outbound proxy configuration.
544
+
545
+ | Field | JSON Key | Type | Description |
546
+ |-------|----------|------|-------------|
547
+ | `service_type` | `sipAccessServiceType` | `str` | What the proxy is used for |
548
+ | `dns_type` | `dnsType` | `str` | DNS record type |
549
+ | `proxy_address` | `outboundProxy` | `str` | Hostname of the proxy |
550
+ | `srv_prefix` | `srvPrefix` | `Optional[str]` | SRV prefix (if DNS type is SRV) |
551
+ | `cname_records` | `cnameRecords` | `Optional[str]` | Associated CNAME records |
552
+ | `attachment_updated` | `attachmentUpdated` | `bool` | Whether proxy was updated (excluded from serialization) |
553
+
554
+ ### BargeInSettings
555
+
556
+ Dataclass with `dataclass_json` serialization. Works for both Person and Workspace.
557
+
558
+ | Field | JSON Key | Type | Description |
559
+ |-------|----------|------|-------------|
560
+ | `parent` | -- | `object` | The Person or Workspace that owns these settings |
561
+ | `enabled` | `enabled` | `bool` | Whether barge-in is enabled |
562
+ | `tone_enabled` | `toneEnabled` | `bool` | Whether barge-in tone is enabled |
563
+
564
+ **Methods:**
565
+
566
+ ```python
567
+ def set_enabled(self, enabled: bool) -> bool
568
+ ```
569
+ PUTs the updated enabled state. Returns True on success.
570
+
571
+ ```python
572
+ def set_tone_enabled(self, enabled: bool) -> bool
573
+ ```
574
+ PUTs the updated tone state. Returns True on success.
575
+
576
+ API endpoint is determined by parent type:
577
+ - Person: `v1/people/{id}/features/bargeIn`
578
+ - Workspace: `v1/telephony/config/workspaces/{id}/bargeIn`
579
+
580
+ ---
581
+
582
+ ## Exception Hierarchy
583
+
584
+ **Module:** `wxcadm/exceptions.py`
585
+
586
+ ```
587
+ Exception
588
+ +-- OrgError # Org-related problems
589
+ | +-- LicenseError # License problems within the org
590
+ | +-- NotSubscribedForLicenseError # Not subscribed for a feature's license
591
+ | +-- LicenseOverageError # Exceeded license limit
592
+ +-- APIError # API communication problems
593
+ +-- TokenError # Access token rejected/invalid
594
+ +-- PutError # PUT operation failed
595
+ +-- XSIError # XSI API problems
596
+ | +-- NotAllowed # XSI action not allowed by platform/user settings
597
+ +-- CSDMError # CSDM-related errors
598
+ ```
599
+
600
+ **Where raised:**
601
+
602
+ | Exception | Raised by |
603
+ |-----------|-----------|
604
+ | `TokenError` | `Webex.__init__` when token is rejected |
605
+ | `OrgError` | `Webex.__init__` when no orgs found or `org_id` not found |
606
+ | `APIError` | `WebexApi` methods and `webex_api_call()` on non-retryable HTTP errors |
607
+ | `LicenseError` | `WebexLicenseList.get_assignable_license()` when no license in assignable subscriptions |
608
+ | `LicenseOverageError` | `WebexLicenseList.get_assignable_license()` when all licenses consumed |
609
+ | `NotSubscribedForLicenseError` | `WebexLicenseList.get_assignable_license()` when license type not found |
610
+
611
+ ---
612
+
613
+ ## Package Exports
614
+
615
+ **Module:** `wxcadm/__init__.py`
616
+
617
+ The `__init__.py` uses star-imports from most submodules to make the entire API surface available from `import wxcadm`. Key explicit imports:
618
+
619
+ - `wxcadm.Webex` -- entry point
620
+ - `wxcadm.Org`, `wxcadm.WebexLicenseList`, `wxcadm.WebexLicense` -- org management
621
+ - `wxcadm.WebexApi` -- HTTP client (from common)
622
+ - All exception classes
623
+ - All feature modules: person, location, call_queue, hunt_group, auto_attendant, workspace, virtual_line, device, number, call_routing, webhooks, announcements, recording, monitoring, dect, pstn, reports, jobs, pickup_group, models
624
+
625
+ ---
626
+
627
+ ## wxcadm vs. wxc_sdk Comparison
628
+
629
+ | Dimension | wxcadm | wxc_sdk |
630
+ |-----------|--------|---------|
631
+ | **Author** | Community / Kris Odoms | Cisco DevNet (official) |
632
+ | **Data model** | Mutable class instances with lazy-loaded properties | Pydantic/dataclass models, mostly immutable |
633
+ | **API transport** | `WebexApi` (session-based, auto-pagination, 429 retry) + legacy `webex_api_call()` | `WebexSimpleApi` with typed method signatures per endpoint |
634
+ | **Org scoping** | `WebexApi` auto-injects `orgId` param when scoped to an Org | Explicit `org_id` param on each API call |
635
+ | **Collection pattern** | Custom `UserList` subclasses (e.g. `PersonList`, `LocationList`) with `.get()` helpers | Returns plain lists or generators of typed objects |
636
+ | **Object hierarchy** | `Webex -> Org -> [People, Locations, ...]` with back-references to parent | Flat API -- no parent references, each call is independent |
637
+ | **Rate limiting** | Built-in 429 retry with `Retry-After` header | Built-in 429 retry |
638
+ | **XSI support** | Yes -- XSI events, calls, call queues | No |
639
+ | **CPAPI support** | Yes -- `wxcadm/cpapi.py` provides `CPAPI` class (VM pin, numbers, workspace caller ID, MOH, AA greetings). Auto-init in `Org.__init__` is commented out; must instantiate manually. Some methods deprecated as public APIs replaced them. | No |
640
+ | **Pagination** | Automatic (follows `r.links['next']`) | Automatic |
641
+ | **Auth patterns** | Token, Integration refresh, Service App flow | Token, Integration, Service App, JWT |
642
+ | **Typical use** | Admin scripts, bulk provisioning, monitoring | Any Webex integration, broader API coverage |
643
+
644
+ **When to use wxcadm:**
645
+ - You need XSI event subscriptions or real-time call control
646
+ - You want an object model where `person.org.locations` traversal is natural
647
+ - You need CPAPI access (manual `CPAPI` instantiation required; auto-init is commented out in current version)
648
+ - You're building admin/provisioning scripts and prefer the lazy-loaded collection pattern
649
+
650
+ **When to use wxc_sdk:**
651
+ - You need broader Webex API coverage (meetings, messaging, etc.)
652
+ - You prefer typed/validated request and response models
653
+ - You want the officially maintained Cisco library
654
+
655
+ ---
656
+
657
+ ## Quickstart
658
+
659
+ From the official docs:
660
+
661
+ ```python
662
+ import wxcadm
663
+
664
+ access_token = "your_api_access_token"
665
+ webex = wxcadm.Webex(access_token)
666
+
667
+ # Single-org admin (most common)
668
+ org = webex.org
669
+
670
+ # Iterate people
671
+ for person in org.people:
672
+ print(person.email)
673
+
674
+ # Access locations
675
+ for location in org.locations:
676
+ print(location.name)
677
+ ```
678
+
679
+ ### Enabling Debug Logging
680
+
681
+ ```python
682
+ wxcadm.console_logging("debug")
683
+ ```
684
+
685
+ ### Service Application Token Flow
686
+
687
+ ```python
688
+ # Developer creates the service app
689
+ developer_webex = wxcadm.Webex(developer_token)
690
+ new_app = developer_webex.org.applications.create_service_application(
691
+ name='My App',
692
+ contact='help@example.com',
693
+ logo='https://example.com/logo.png',
694
+ scopes=['spark:people_read', 'spark-admin:people_write', ...]
695
+ )
696
+ app_id = new_app['id']
697
+ client_secret = new_app['clientSecret']
698
+
699
+ # Admin authorizes
700
+ admin_webex = wxcadm.Webex(admin_token)
701
+ app = admin_webex.org.applications.get_app_by_id(app_id)
702
+ app.authorize()
703
+
704
+ # Developer gets token for admin's org
705
+ app = developer_webex.org.applications.get_app_by_id(app_id)
706
+ token_info = app.get_token(client_secret, admin_org_id)
707
+ # token_info keys: access_token, expires_in, refresh_token,
708
+ # refresh_token_expires_in, token_type
709
+
710
+ # Refresh when needed
711
+ token_info = app.get_token_refresh(client_secret, refresh_token)
712
+ ```
713
+
714
+ ### Token Refresh (Integration)
715
+
716
+ ```python
717
+ webex = wxcadm.Webex(
718
+ access_token,
719
+ client_id="...",
720
+ client_secret="...",
721
+ refresh_token="...",
722
+ )
723
+
724
+ # Later, when token is about to expire:
725
+ new_token_info = webex.get_new_token()
726
+ # The Webex instance is updated in-place with the new token
727
+ ```
728
+
729
+ ---
730
+
731
+ ## Gotchas
732
+
733
+ - **`auto_refresh_token` is not production-ready.** The constructor accepts `auto_refresh_token=True` but the docs explicitly say it is "still in development -- do not use." Token refresh must be done manually via `get_new_token()`.
734
+ - **`get_xsi` is a hidden kwargs parameter.** It does not appear in the explicit constructor signature -- it is passed through `**kwargs` to `Org` creation. Easy to miss when reading the API surface.
735
+ - **`read_only=True` skips org discovery.** It uses `/v1/people/me` instead of `/v1/organizations`, so `self.orgs` will contain only one org derived from the token owner's identity. This mode does not require admin scope but gives a limited view.
736
+ - **Legacy `webex_api_call()` is still in the codebase.** Some modules still use it instead of `WebexApi`. It creates a new `requests.Session` per call (no connection reuse), so it is less efficient. Prefer `org.api` methods in new code.
737
+ - **`get_recordings()` kwargs are passed through to `RecordingList`.** The method signature accepts `**kwargs` which map to `RecordingList.__init__` parameters: `from_date_time`, `to_date_time`, `status`, `service` (maps to API `serviceType`), `owner` (Person/Workspace/VirtualLine), `region` (maps to API `storageRegion`), `location` (Location object).
738
+ - **CPAPI support exists but auto-init is disabled.** The `CPAPI` class in `wxcadm/cpapi.py` provides methods for VM pin management, numbers (deprecated), workspace caller ID, MOH file upload/config, and AA greeting upload/config. However, the auto-instantiation line in `Org.__init__` is commented out (`#self._cpapi = CPAPI(...)`). To use CPAPI, instantiate manually: `cpapi = CPAPI(org, access_token)`. Several methods have been superseded by public developer APIs (e.g., `reset_vm_pin`, `get_numbers`).
739
+
740
+ ## See Also
741
+
742
+ - [authentication.md](authentication.md) — wxc_sdk authentication patterns, token management, and Service App flows
743
+ - [wxc-sdk-patterns.md](wxc-sdk-patterns.md) — wxc_sdk architectural patterns and API transport for comparison with wxcadm's `WebexApi`