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,1255 @@
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. PersonList(org, location) signature, PersonList.all(), Person(org=) constructor, Person.single_number_reach, Person.appearance_devices, Person.delete(), PersonList.get_by_email() removal, get_barge_in/push_barge_in removal — all accurately documented. No discrepancies found. -->
3
+ # wxcadm — Person Module Reference
4
+
5
+ Source: `wxcadm/person.py`
6
+
7
+ This document covers every class, method, and property in the wxcadm `person` module. The module provides person/user management for Webex Calling orgs, including user CRUD, call settings, device management, number management, and ancillary models like UserGroups, SingleNumberReach, and ApplicationServicesSettings.
8
+
9
+ ---
10
+
11
+ <!-- Updated by playbook session 2026-03-18 -->
12
+ ## When to Use wxcadm vs Raw HTTP
13
+
14
+ wxcadm Person has 34 call settings methods, but most wrap standard Webex REST endpoints that raw HTTP can call directly. The truly unique capabilities are the ones worth using wxcadm for.
15
+
16
+ | Use wxcadm when | Use raw HTTP when |
17
+ |---|---|
18
+ | You need **XSI session management** — `start_xsi()` has no raw HTTP equivalent | You're reading/writing standard person call settings (forwarding, voicemail, DND, etc.) |
19
+ | You need **reverse membership lookups** — `person.hunt_groups`, `person.call_queues` search the org for you | You're doing targeted CRUD on a known person ID |
20
+ | You want **`get_full_config()`** to batch-fetch all settings at once | You want to read/write a single setting without loading the full person object |
21
+ | You need **`ecbn_null_change()`** — a backend bug workaround not in wxc_sdk | You're building automation that needs predictable, minimal API calls |
22
+ | You want **`ApplicationLineAssignments`** for shared call appearance management | You're working with well-documented endpoints that don't need convenience wrappers |
23
+ | You need **`spark_id`** decoding or **`set_calling_only()`** license cleanup | You want Pydantic-typed responses (use wxc_sdk models with raw HTTP instead) |
24
+
25
+ > **Note:** The playbook uses raw HTTP via `api.session.rest_*()` for standard person CRUD and call settings. wxcadm is used for its truly unique capabilities: XSI integration, reverse group lookups, `ecbn_null_change()`, `get_full_config()` batch fetch, and `ApplicationLineAssignments`. Convenience methods like `set_caller_id()` and `enable_call_recording()` are nice but replaceable with raw HTTP + the correct payload.
26
+
27
+ ---
28
+
29
+ ## Table of Contents
30
+
31
+ - [PersonList](#personlist)
32
+ - [Person](#person)
33
+ - [User Info & Management](#user-info--management)
34
+ - [Call Settings](#call-settings)
35
+ - [Number Management](#number-management)
36
+ - [Device Management](#device-management)
37
+ - [Permissions & Access](#permissions--access)
38
+ - [Monitoring & Group Membership](#monitoring--group-membership)
39
+ - [XSI](#xsi)
40
+ - [Me (subclass of Person)](#me)
41
+ - [Data Models](#data-models)
42
+ - [VoiceMessage](#voicemessage)
43
+ - [UserGroups / UserGroup](#usergroups--usergroup)
44
+ - [ApplicationServicesSettings](#applicationservicessettings)
45
+ - [ApplicationLineAssignments / ApplicationLine](#applicationlineassignments--applicationline)
46
+ - [SingleNumberReach / SnrNumber](#singlenumberreach--snrnumber)
47
+ - [wxcadm vs wxc_sdk](#wxcadm-vs-wxc_sdk)
48
+
49
+ ---
50
+
51
+ ## PersonList
52
+
53
+ Extends `collections.UserList`. Lazy-loads people from the Webex `v1/people` API with `callingData=true`.
54
+
55
+ ### Constructor
56
+
57
+ ```python
58
+ PersonList(org: wxcadm.Org, location: Optional[wxcadm.Location] = None)
59
+ ```
60
+
61
+ Internal state flags:
62
+ - `__data_loaded` — tracks whether any data has been fetched
63
+ - `__data_filtered` — tracks whether `self.data` is a filtered subset
64
+ - `__filters` — remembers the last filter dict used for `refresh()`
65
+
66
+ ### Methods
67
+
68
+ #### `get`
69
+
70
+ ```python
71
+ def get(
72
+ self,
73
+ id: Optional[str] = None,
74
+ email: Optional[str] = None,
75
+ name: Optional[str] = None,
76
+ location: Optional[wxcadm.Location] = None,
77
+ uuid: Optional[str] = None
78
+ ) -> Union[Person, PersonList]
79
+ ```
80
+
81
+ Unified getter. Returns a single `Person` when exactly one result is found (and no location scope), otherwise returns the `PersonList` itself. Uses cached data for `id`/`email` lookups when data is already loaded and unfiltered.
82
+
83
+ - `name` matches against `display_name` (case-insensitive, full match, sent as `displayName` API param)
84
+ - `uuid` is sent as the `id` API filter — used primarily for CDR correlation
85
+
86
+ #### `get_by_id`
87
+
88
+ ```python
89
+ def get_by_id(self, id: str) -> Optional[Person]
90
+ ```
91
+
92
+ Linear search through already-loaded `self.data`. Does not make API calls.
93
+
94
+ #### `all`
95
+
96
+ ```python
97
+ def all(self) -> Union[Person, PersonList]
98
+ ```
99
+
100
+ Resets `__data_loaded` flag and calls `get()` with no filters. Returns all people in the org.
101
+
102
+ #### `refresh`
103
+
104
+ ```python
105
+ def refresh(self) -> None
106
+ ```
107
+
108
+ Re-fetches the list using the same filters from the last `get()` call.
109
+
110
+ #### `webex_calling`
111
+
112
+ ```python
113
+ def webex_calling(self, enabled: bool = True) -> list[Person]
114
+ ```
115
+
116
+ Filters the loaded list to people where `Person.wxc` matches `enabled`. Lazy-loads data if not already loaded.
117
+
118
+ #### `recorded`
119
+
120
+ ```python
121
+ def recorded(self, enabled: bool = True) -> list[Person]
122
+ ```
123
+
124
+ Returns people whose call recording `enabled` flag matches the argument. Calls `get_call_recording()` on each WxC-enabled person — can be slow on large orgs.
125
+
126
+ #### `create`
127
+
128
+ ```python
129
+ def create(
130
+ self,
131
+ email: str,
132
+ location: Optional[Union[str, Location]] = None,
133
+ licenses: list = None,
134
+ calling: bool = True,
135
+ phone_number: str = None,
136
+ extension: str = None,
137
+ first_name: str = None,
138
+ last_name: str = None,
139
+ display_name: str = None
140
+ ) -> Person
141
+ ```
142
+
143
+ Creates a new user via `POST v1/people`. If `licenses` is not provided and `calling=True`, automatically finds a Professional Calling license. If no names are given, `display_name` defaults to the email.
144
+
145
+ Raises `wxcadm.exceptions.LicenseError` if no calling license is available.
146
+ Raises `wxcadm.exceptions.PutError` if creation fails.
147
+
148
+ ---
149
+
150
+ ## Person
151
+
152
+ ### Constructor
153
+
154
+ ```python
155
+ Person(user_id: str, org: wxcadm.Org, config: Optional[dict] = None)
156
+ ```
157
+
158
+ If `config` is omitted, makes a `GET v1/people/{user_id}?callingData=true` call. The `wxc` flag is set to `True` only when the person has both a Webex Calling license AND an assigned location.
159
+
160
+ ### Instance Attributes
161
+
162
+ | Attribute | Type | Description |
163
+ |-----------|------|-------------|
164
+ | `id` | `str` | Webex person ID |
165
+ | `org` | `wxcadm.Org` | Parent org |
166
+ | `email` | `str` | Primary email |
167
+ | `first_name` | `str` | First name |
168
+ | `last_name` | `str` | Last name |
169
+ | `display_name` | `str` | Display name |
170
+ | `wxc` | `bool` | True if Webex Calling enabled |
171
+ | `licenses` | `list` | License IDs |
172
+ | `location` | `str` | Location ID |
173
+ | `roles` | `list` | Role IDs |
174
+ | `numbers` | `list` | Phone numbers from Common Identity (list of dicts with `type`/`value`) |
175
+ | `extension` | `Optional[str]` | Extension |
176
+ | `avatar` | `Optional[str]` | Avatar URL |
177
+ | `department` | `Optional[str]` | Department |
178
+ | `manager` | `Optional[str]` | Manager name |
179
+ | `manager_id` | `Optional[str]` | Manager's person ID |
180
+ | `title` | `Optional[str]` | Job title |
181
+ | `addresses` | `Optional[list]` | Addresses |
182
+ | `status` | `Optional[str]` | Presence status |
183
+ | `login_enabled` | `Optional[bool]` | Whether sign-in is allowed |
184
+ | `xsi` | `Optional[XSI]` | XSI session (set by `start_xsi()`) |
185
+
186
+ Settings dicts (populated by their respective `get_*` methods):
187
+
188
+ | Attribute | Populated By |
189
+ |-----------|-------------|
190
+ | `vm_config` | `get_vm_config()` |
191
+ | `call_recording` | `get_call_recording()` |
192
+ | `call_forwarding` | `get_call_forwarding()` |
193
+ | `caller_id` | `get_caller_id()` |
194
+ | `intercept` | `get_intercept()` |
195
+ | `dnd` | `get_dnd()` |
196
+ | `calling_behavior` | `get_calling_behavior()` |
197
+ | `hoteling` | `get_hoteling()` |
198
+ | `ptt` | `get_ptt()` |
199
+ | `outgoing_permission` | `get_outgoing_permission()` |
200
+ | `executive_assistant` | `get_executive_assistant()` |
201
+ | `applications_settings` | `get_applications_settings()` |
202
+
203
+ ---
204
+
205
+ ### User Info & Management
206
+
207
+ #### Properties
208
+
209
+ ##### `org_id`
210
+
211
+ ```python
212
+ @property
213
+ def org_id(self) -> Optional[str]
214
+ ```
215
+
216
+ Returns `self.org.id`.
217
+
218
+ ##### `spark_id`
219
+
220
+ ```python
221
+ @property
222
+ def spark_id(self) -> str
223
+ ```
224
+
225
+ Base64-decodes the person ID to get the internal Webex/Spark identifier. Useful for internal correlation.
226
+
227
+ ##### `name`
228
+
229
+ ```python
230
+ @property
231
+ def name(self) -> str
232
+ ```
233
+
234
+ Alias for `display_name`.
235
+
236
+ #### Methods
237
+
238
+ ##### `role_names`
239
+
240
+ ```python
241
+ def role_names(self) -> Optional[list]
242
+ ```
243
+
244
+ Returns a list of role name strings by resolving role IDs against `self.org.roles`. Returns `None` if the person has no roles.
245
+
246
+ > **Note:** There is a bug in the source — `return roles` is inside the `for` loop (line 483 of person.py), so only the first role is ever returned.
247
+
248
+ ##### `delete`
249
+
250
+ ```python
251
+ def delete(self) -> bool
252
+ ```
253
+
254
+ Deletes the person via `DELETE v1/people/{id}`.
255
+
256
+ ##### `refresh_person`
257
+
258
+ ```python
259
+ def refresh_person(self, raw: bool = False) -> Union[bool, dict]
260
+ ```
261
+
262
+ Re-fetches person details from the API and updates instance attributes. If `raw=True`, returns the raw API dict.
263
+
264
+ ##### `update_person`
265
+
266
+ ```python
267
+ def update_person(
268
+ self,
269
+ email=None,
270
+ numbers=None,
271
+ extension=None,
272
+ location=None,
273
+ display_name=None,
274
+ first_name=None,
275
+ last_name=None,
276
+ roles=None,
277
+ licenses=None,
278
+ avatar: Optional[str] = None,
279
+ department: Optional[str] = None,
280
+ title: Optional[str] = None,
281
+ addresses: Optional[list] = None
282
+ ) -> bool
283
+ ```
284
+
285
+ PUT update to `v1/people/{id}`. Any omitted argument uses the current instance value as the default, so you can modify an instance attribute directly (e.g., `person.extension = "1234"`) then call `update_person()` with no args to push the change.
286
+
287
+ ##### `license_details`
288
+
289
+ ```python
290
+ def license_details(self) -> list
291
+ ```
292
+
293
+ Returns the full license objects (from `org.licenses`) for all licenses assigned to this person.
294
+
295
+ ##### `assign_wxc`
296
+
297
+ ```python
298
+ def assign_wxc(
299
+ self,
300
+ location: wxcadm.Location,
301
+ phone_number: Optional[str] = None,
302
+ extension: Optional[str] = None,
303
+ unassign_ucm: Optional[bool] = False,
304
+ license_type: Optional[str] = 'professional',
305
+ ignore_license_overage: Optional[bool] = True
306
+ ) -> bool
307
+ ```
308
+
309
+ Assigns Webex Calling to the user. Finds the appropriate license automatically. `license_type` can be `'standard'` or `'professional'`. If `unassign_ucm=True`, removes UCM licenses first.
310
+
311
+ ##### `unassign_wxc`
312
+
313
+ ```python
314
+ def unassign_wxc(self) -> bool
315
+ ```
316
+
317
+ Removes all Webex Calling licenses and clears the extension.
318
+
319
+ ##### `set_calling_only`
320
+
321
+ ```python
322
+ def set_calling_only(self) -> bool
323
+ ```
324
+
325
+ Removes Messaging and Meetings licenses, keeping only Calling (and screen share). Uses `update_person()` internally.
326
+
327
+ ---
328
+
329
+ ### Call Settings
330
+
331
+ All `get_*` methods store their result on the corresponding instance attribute and also return it. All `push_*` methods accept a config dict and send it via PUT.
332
+
333
+ #### Voicemail
334
+
335
+ ##### `get_vm_config`
336
+
337
+ ```python
338
+ def get_vm_config(self) -> dict
339
+ ```
340
+
341
+ `GET v1/people/{id}/features/voicemail`
342
+
343
+ ##### `push_vm_config`
344
+
345
+ ```python
346
+ def push_vm_config(self, vm_config: dict = None) -> Union[dict, bool]
347
+ ```
348
+
349
+ `PUT v1/people/{id}/features/voicemail`. If `vm_config` is omitted, pushes `self.vm_config`. Returns the refreshed config on success, `False` on failure.
350
+
351
+ ##### `reset_vm_pin`
352
+
353
+ ```python
354
+ def reset_vm_pin(self, pin: str = None) -> bool
355
+ ```
356
+
357
+ If `pin` is provided, sets it directly via `PUT .../voicemail/passcode`. If omitted, triggers a reset that sends a temporary PIN to the user by email.
358
+
359
+ ##### `enable_vm_to_email`
360
+
361
+ ```python
362
+ def enable_vm_to_email(self, email: str = None, push: bool = True) -> dict
363
+ ```
364
+
365
+ Enables sending VM copies to email. Defaults to the person's own email.
366
+
367
+ ##### `disable_vm_to_email`
368
+
369
+ ```python
370
+ def disable_vm_to_email(self, push: bool = True) -> dict
371
+ ```
372
+
373
+ Disables VM-to-email.
374
+
375
+ ##### `enable_vm_notification`
376
+
377
+ ```python
378
+ def enable_vm_notification(self, email: str = None, push: bool = True) -> dict
379
+ ```
380
+
381
+ Enables VM notification to email. Defaults to the person's own email.
382
+
383
+ ##### `disable_vm_notification`
384
+
385
+ ```python
386
+ def disable_vm_notification(self, email: str = None, push: bool = True) -> dict
387
+ ```
388
+
389
+ Disables VM notification.
390
+
391
+ ##### `set_voicemail_rings`
392
+
393
+ ```python
394
+ def set_voicemail_rings(self, rings: int, push: bool = True) -> dict
395
+ ```
396
+
397
+ Sets the number of rings before unanswered calls go to voicemail.
398
+
399
+ ##### `upload_busy_greeting`
400
+
401
+ ```python
402
+ def upload_busy_greeting(self, filename: str, activate: bool = True) -> bool
403
+ ```
404
+
405
+ Uploads a WAV file as the busy greeting via multipart POST. If `activate=True`, also sets the greeting type to `CUSTOM`. No format validation is performed.
406
+
407
+ ##### `upload_no_answer_greeting`
408
+
409
+ ```python
410
+ def upload_no_answer_greeting(self, filename: str, activate: bool = True) -> bool
411
+ ```
412
+
413
+ Uploads a WAV file as the no-answer greeting. Same behavior as `upload_busy_greeting`.
414
+
415
+ #### Call Forwarding
416
+
417
+ ##### `get_call_forwarding`
418
+
419
+ ```python
420
+ def get_call_forwarding(self) -> dict
421
+ ```
422
+
423
+ `GET v1/people/{id}/features/callForwarding`
424
+
425
+ ##### `push_cf_config`
426
+
427
+ ```python
428
+ def push_cf_config(self, cf_config: dict = None) -> Union[dict, bool]
429
+ ```
430
+
431
+ `PUT v1/people/{id}/features/callForwarding`. If `cf_config` is omitted, pushes `self.call_forwarding`.
432
+
433
+ #### Caller ID
434
+
435
+ ##### `get_caller_id`
436
+
437
+ ```python
438
+ def get_caller_id(self) -> dict
439
+ ```
440
+
441
+ `GET v1/people/{id}/features/callerId`
442
+
443
+ ##### `push_caller_id`
444
+
445
+ ```python
446
+ def push_caller_id(self, config: dict) -> bool
447
+ ```
448
+
449
+ `PUT v1/people/{id}/features/callerId`. Sends the raw config dict. For a friendlier interface, use `set_caller_id()`.
450
+
451
+ ##### `set_caller_id`
452
+
453
+ ```python
454
+ def set_caller_id(self, name: str, number: str) -> bool
455
+ ```
456
+
457
+ Convenience method that builds the correct API payload from keywords:
458
+
459
+ | `name` value | API field set |
460
+ |-------------|--------------|
461
+ | `"direct"` | `externalCallerIdNamePolicy: "DIRECT_LINE"` |
462
+ | `"location"` | `externalCallerIdNamePolicy: "LOCATION"` |
463
+ | anything else | `externalCallerIdNamePolicy: "OTHER"`, `customExternalCallerIdName: name` |
464
+
465
+ | `number` value | API field set |
466
+ |---------------|--------------|
467
+ | `"direct"` | `selected: "DIRECT_LINE"` |
468
+ | `"location"` | `selected: "LOCATION_NUMBER"` |
469
+ | anything else | `selected: "CUSTOM"`, `customNumber: number` |
470
+
471
+ #### Call Recording
472
+
473
+ ##### `get_call_recording`
474
+
475
+ ```python
476
+ def get_call_recording(self) -> dict
477
+ ```
478
+
479
+ `GET v1/people/{id}/features/callRecording`
480
+
481
+ ##### `push_call_recording`
482
+
483
+ ```python
484
+ def push_call_recording(self, config: dict) -> bool
485
+ ```
486
+
487
+ `PUT v1/people/{id}/features/callRecording`. Automatically strips Dubber-specific keys (`serviceProvider`, `externalGroup`, `externalIdentifier`) before sending, since the PUT endpoint does not accept them.
488
+
489
+ ##### `enable_call_recording`
490
+
491
+ ```python
492
+ def enable_call_recording(
493
+ self,
494
+ type: str,
495
+ record_vm: bool = False,
496
+ announcement_enabled: bool = False,
497
+ reminder_tone: bool = False,
498
+ reminder_interval: int = 30,
499
+ can_play: bool = True,
500
+ can_download: bool = True,
501
+ can_delete: bool = True,
502
+ can_share: bool = True,
503
+ transcribe: bool = True,
504
+ ai_summary: bool = True
505
+ ) -> bool
506
+ ```
507
+
508
+ `type` must be one of: `'always'`, `'never'`, `'always_with_pause'`, `'on_demand'`.
509
+
510
+ Raises `ValueError` for invalid type values.
511
+
512
+ > **Note:** `transcribe`, `can_play`, and similar params only apply when Webex platform recording is used. Third-party recording providers ignore them.
513
+
514
+ ##### `disable_call_recording`
515
+
516
+ ```python
517
+ def disable_call_recording(self) -> bool
518
+ ```
519
+
520
+ Sets `enabled: False` and pushes.
521
+
522
+ #### Call Intercept
523
+
524
+ ##### `get_intercept`
525
+
526
+ ```python
527
+ def get_intercept(self) -> dict
528
+ ```
529
+
530
+ `GET v1/people/{id}/features/intercept`
531
+
532
+ ##### `push_intercept`
533
+
534
+ ```python
535
+ def push_intercept(self, config: dict) -> bool
536
+ ```
537
+
538
+ `PUT v1/people/{id}/features/intercept`
539
+
540
+ #### Do Not Disturb
541
+
542
+ ##### `get_dnd`
543
+
544
+ ```python
545
+ def get_dnd(self) -> dict
546
+ ```
547
+
548
+ `GET v1/people/{id}/features/doNotDisturb`
549
+
550
+ ##### `push_dnd`
551
+
552
+ ```python
553
+ def push_dnd(self, config: dict) -> bool
554
+ ```
555
+
556
+ `PUT v1/people/{id}/features/doNotDisturb`
557
+
558
+ #### Calling Behavior
559
+
560
+ ##### `get_calling_behavior`
561
+
562
+ ```python
563
+ def get_calling_behavior(self) -> dict
564
+ ```
565
+
566
+ `GET v1/people/{id}/features/callingBehavior`
567
+
568
+ ##### `push_calling_behavior`
569
+
570
+ ```python
571
+ def push_calling_behavior(self, config: dict) -> bool
572
+ ```
573
+
574
+ `PUT v1/people/{id}/features/callingBehavior`
575
+
576
+ #### Hoteling
577
+
578
+ ##### `get_hoteling`
579
+
580
+ ```python
581
+ def get_hoteling(self) -> dict
582
+ ```
583
+
584
+ `GET v1/people/{id}/features/hoteling`
585
+
586
+ ##### `push_hoteling`
587
+
588
+ ```python
589
+ def push_hoteling(self, config: dict) -> bool
590
+ ```
591
+
592
+ `PUT v1/people/{id}/features/hoteling`. Re-fetches after success.
593
+
594
+ #### Push-to-Talk
595
+
596
+ ##### `get_ptt`
597
+
598
+ ```python
599
+ def get_ptt(self) -> dict
600
+ ```
601
+
602
+ `GET v1/people/{id}/features/pushToTalk`
603
+
604
+ ##### `push_ptt`
605
+
606
+ ```python
607
+ def push_ptt(self, config: dict) -> bool
608
+ ```
609
+
610
+ `PUT v1/people/{id}/features/pushToTalk`
611
+
612
+ #### Executive Assistant
613
+
614
+ ##### `get_executive_assistant`
615
+
616
+ ```python
617
+ def get_executive_assistant(self) -> dict
618
+ ```
619
+
620
+ `GET v1/people/{id}/features/executiveAssistant`
621
+
622
+ ##### `push_executive_assistant`
623
+
624
+ ```python
625
+ def push_executive_assistant(self, config: dict) -> bool
626
+ ```
627
+
628
+ `PUT v1/people/{id}/features/executiveAssistant`
629
+
630
+ #### Application Services
631
+
632
+ ##### `get_applications_settings`
633
+
634
+ ```python
635
+ def get_applications_settings(self) -> dict
636
+ ```
637
+
638
+ `GET v1/people/{id}/features/applications`. Returns the raw dict.
639
+
640
+ ##### `push_applications_settings`
641
+
642
+ ```python
643
+ def push_applications_settings(self, config: dict) -> bool
644
+ ```
645
+
646
+ `PUT v1/people/{id}/features/applications`
647
+
648
+ ##### `applications` (property)
649
+
650
+ ```python
651
+ @property
652
+ def applications(self) -> ApplicationServicesSettings
653
+ ```
654
+
655
+ Returns a lazy-loaded `ApplicationServicesSettings` dataclass instance. See [ApplicationServicesSettings](#applicationservicessettings) for its methods.
656
+
657
+ #### Barge-In
658
+
659
+ ##### `barge_in` (property)
660
+
661
+ ```python
662
+ @property
663
+ def barge_in(self) -> Optional[BargeInSettings]
664
+ ```
665
+
666
+ Returns a lazy-loaded `BargeInSettings` dataclass. Fetches from `GET v1/people/{id}/features/bargeIn`.
667
+
668
+ #### Single Number Reach
669
+
670
+ ##### `single_number_reach` (property)
671
+
672
+ ```python
673
+ @property
674
+ def single_number_reach(self) -> SingleNumberReach
675
+ ```
676
+
677
+ Returns a lazy-loaded `SingleNumberReach` instance. See [SingleNumberReach](#singlenumberreach--snrnumber).
678
+
679
+ #### Outgoing Permission
680
+
681
+ ##### `get_outgoing_permission`
682
+
683
+ ```python
684
+ def get_outgoing_permission(self) -> dict
685
+ ```
686
+
687
+ `GET v1/people/{id}/features/outgoingPermission`
688
+
689
+ ##### `push_outgoing_permission`
690
+
691
+ ```python
692
+ def push_outgoing_permission(self, config: dict) -> bool
693
+ ```
694
+
695
+ `PUT v1/people/{id}/features/outgoingPermission`
696
+
697
+ #### Preferred Answer Endpoint
698
+
699
+ ##### `preferred_answer_endpoint` (property)
700
+
701
+ ```python
702
+ @property
703
+ def preferred_answer_endpoint(self) -> Union[dict, None]
704
+ ```
705
+
706
+ `GET v1/telephony/config/people/{id}/preferredAnswerEndpoint`. Returns the dict for the currently preferred endpoint, or `None` if not set.
707
+
708
+ ##### `set_preferred_answer_endpoint`
709
+
710
+ ```python
711
+ def set_preferred_answer_endpoint(self, endpoint: Union[wxcadm.Device, str]) -> bool
712
+ ```
713
+
714
+ Sets the preferred answer endpoint. Accepts a `Device` instance or a string ID.
715
+
716
+ > **Note:** Cisco 9800 (PhoneOS) devices do not work with this API endpoint due to an API-side issue.
717
+
718
+ ##### `available_answer_endpoints` (property)
719
+
720
+ ```python
721
+ @property
722
+ def available_answer_endpoints(self) -> Optional[list[Union[Device, str]]]
723
+ ```
724
+
725
+ Returns a list of `Device` objects (for type `DEVICE`) and string IDs (for type `APPLICATION`). Cached after first access.
726
+
727
+ #### Bulk Config Fetch
728
+
729
+ ##### `get_full_config`
730
+
731
+ ```python
732
+ def get_full_config(self) -> Union[Person, bool]
733
+ ```
734
+
735
+ Fetches all calling settings in one call: forwarding, voicemail, caller ID, recording, DND, calling behavior, hoteling, intercept, outgoing permission, and PTT. Returns `self` on success, `False` if the person is not a WxC user.
736
+
737
+ ---
738
+
739
+ ### Number Management
740
+
741
+ ##### `wxc_numbers` (property)
742
+
743
+ ```python
744
+ @property
745
+ def wxc_numbers(self) -> dict
746
+ ```
747
+
748
+ `GET v1/people/{id}/features/numbers`. Returns numbers from the Webex Calling platform (not Common Identity). Includes the primary number and any aliases. Unlike `self.numbers`, this does not include Active Directory data.
749
+
750
+ ##### `change_phone_number`
751
+
752
+ ```python
753
+ def change_phone_number(self, new_number: str, new_extension: str = None) -> bool
754
+ ```
755
+
756
+ Changes the person's phone number (and optionally extension) via `update_person()`.
757
+
758
+ ##### `remove_did`
759
+
760
+ ```python
761
+ def remove_did(self) -> str
762
+ ```
763
+
764
+ Removes the `work`-type phone number from the person. Returns the removed number string (useful for re-adding after a user move).
765
+
766
+ ##### `add_did`
767
+
768
+ ```python
769
+ def add_did(self, phone_number: str, primary: Optional[bool] = True) -> list
770
+ ```
771
+
772
+ Adds a DID to the person. Returns the updated numbers list.
773
+
774
+ ##### `ecbn` (property)
775
+
776
+ ```python
777
+ @property
778
+ def ecbn(self) -> dict
779
+ ```
780
+
781
+ `GET v1/telephony/config/people/{id}/emergencyCallbackNumber`
782
+
783
+ ##### `set_ecbn`
784
+
785
+ ```python
786
+ def set_ecbn(self, value: Union[str, Person, Workspace, VirtualLine]) -> bool
787
+ ```
788
+
789
+ Sets the Emergency Callback Number. Accepts:
790
+ - `"direct"` or `"direct_line"` — user's own DID
791
+ - `"location"` or `"location_ecbn"` — location ECBN
792
+ - A `Person`, `Workspace`, or `VirtualLine` instance — that entity's number
793
+
794
+ Raises `ValueError` for unknown string values.
795
+
796
+ ##### `ecbn_null_change`
797
+
798
+ ```python
799
+ def ecbn_null_change(self) -> bool
800
+ ```
801
+
802
+ Re-sends the current ECBN config unchanged. Workaround for a backend bug where ECBN settings become out of sync between Control Hub and Webex Calling.
803
+
804
+ ---
805
+
806
+ ### Device Management
807
+
808
+ ##### `devices` (property)
809
+
810
+ ```python
811
+ @property
812
+ def devices(self) -> DeviceList
813
+ ```
814
+
815
+ Returns a lazy-loaded `DeviceList` for this person.
816
+
817
+ ##### `appearance_devices` (property)
818
+
819
+ ```python
820
+ @property
821
+ def appearance_devices(self) -> list[dict]
822
+ ```
823
+
824
+ `GET v1/telephony/config/people/{id}/devices`. Returns raw dicts of devices that have this person as a line appearance. Values like `mac` in the returned dicts can be used to cross-reference with `self.devices`.
825
+
826
+ ---
827
+
828
+ ### Permissions & Access
829
+
830
+ ##### `outgoing_permission`
831
+
832
+ See [get_outgoing_permission / push_outgoing_permission](#outgoing-permission) in Call Settings above.
833
+
834
+ ##### `user_groups` (property)
835
+
836
+ ```python
837
+ @property
838
+ def user_groups(self) -> list
839
+ ```
840
+
841
+ Returns the list of `UserGroup` instances that this person is a member of. Delegates to `org.usergroups.find_person_assignments()`.
842
+
843
+ ---
844
+
845
+ ### Monitoring & Group Membership
846
+
847
+ ##### `monitoring` (property)
848
+
849
+ ```python
850
+ @property
851
+ def monitoring(self) -> MonitoringList
852
+ ```
853
+
854
+ Returns a lazy-loaded `MonitoringList` for viewing/controlling monitoring. Fetches from `GET v1/people/{id}/features/monitoring`.
855
+
856
+ ##### `get_monitored_by`
857
+
858
+ ```python
859
+ def get_monitored_by(self) -> Optional[dict]
860
+ ```
861
+
862
+ Returns a dict of users and workspaces that are monitoring this person. Uses `org.get_all_monitoring()` to get the full org-wide monitoring map.
863
+
864
+ ##### `hunt_groups` (property)
865
+
866
+ ```python
867
+ @property
868
+ def hunt_groups(self) -> list
869
+ ```
870
+
871
+ Returns `HuntGroup` instances where this person is an agent. Iterates all org hunt groups and checks each agent list. Can be slow on large orgs.
872
+
873
+ ##### `call_queues` (property)
874
+
875
+ ```python
876
+ @property
877
+ def call_queues(self) -> list
878
+ ```
879
+
880
+ Returns `CallQueue` instances where this person is an agent. Same iteration approach as `hunt_groups`.
881
+
882
+ ---
883
+
884
+ ### XSI
885
+
886
+ ##### `start_xsi`
887
+
888
+ ```python
889
+ def start_xsi(self, get_profile: bool = False, cache: bool = False) -> XSI
890
+ ```
891
+
892
+ Starts an XSI session for the person. Sets `self.xsi` and returns the `XSI` instance. See `wxcadm-xsi-realtime.md` for XSI details.
893
+
894
+ ---
895
+
896
+ ## Me
897
+
898
+ ```python
899
+ class Me(Person)
900
+ ```
901
+
902
+ Subclass of `Person` representing the token owner. Provides methods only available at owner scope.
903
+
904
+ ### Methods
905
+
906
+ #### `get_voice_messages`
907
+
908
+ ```python
909
+ def get_voice_messages(self, unread: bool = False) -> list[VoiceMessage]
910
+ ```
911
+
912
+ `GET v1/telephony/voiceMessages`. Returns a list of `VoiceMessage` instances. If `unread=True`, filters to unread only.
913
+
914
+ #### `voicemail_summary` (property)
915
+
916
+ ```python
917
+ @property
918
+ def voicemail_summary(self) -> Optional[dict]
919
+ ```
920
+
921
+ `GET v1/telephony/voiceMessages/summary`. Returns a dict:
922
+
923
+ ```python
924
+ {
925
+ 'newMessages': int,
926
+ 'oldMessages': int,
927
+ 'newUrgentMessages': int,
928
+ 'oldUrgentMessages': int
929
+ }
930
+ ```
931
+
932
+ ---
933
+
934
+ ## Data Models
935
+
936
+ ### VoiceMessage
937
+
938
+ ```python
939
+ @dataclass
940
+ class VoiceMessage:
941
+ org: wxcadm.Org
942
+ id: str
943
+ duration: int # seconds; not present for fax
944
+ callingParty: dict # caller details
945
+ read: bool
946
+ created: str # ISO timestamp
947
+ urgent: bool = False
948
+ confidential: bool = False
949
+ faxPageCount: Optional[int] = None
950
+ ```
951
+
952
+ #### Methods
953
+
954
+ | Method | Signature | Description |
955
+ |--------|-----------|-------------|
956
+ | `mark_read` | `() -> bool` | Marks the message as read |
957
+ | `mark_unread` | `() -> bool` | Marks the message as unread |
958
+ | `delete` | `() -> bool` | Deletes the voice message |
959
+
960
+ ---
961
+
962
+ ### UserGroups / UserGroup
963
+
964
+ #### UserGroups (list class)
965
+
966
+ Extends `UserList`. Eagerly fetches all groups from `GET v1/groups` on init.
967
+
968
+ ```python
969
+ UserGroups(org: wxcadm.Org)
970
+ ```
971
+
972
+ ##### Methods
973
+
974
+ | Method | Signature | Description |
975
+ |--------|-----------|-------------|
976
+ | `create_group` | `(name: str, description: str = '', members: Optional[list] = None) -> bool` | Creates a new group. `members` is a list of `Person` instances. |
977
+ | `find_person_assignments` | `(person: Person) -> list[UserGroup]` | Returns all groups containing the given person. |
978
+
979
+ #### UserGroup (dataclass)
980
+
981
+ ```python
982
+ @dataclass
983
+ class UserGroup:
984
+ org: wxcadm.Org
985
+ id: str
986
+ displayName: str
987
+ orgId: str
988
+ created: str
989
+ lastModified: str
990
+ usage: str = 'Unknown' # removed from API response since v3.0.0
991
+ memberSize: int = 0
992
+ description: str = ''
993
+ ```
994
+
995
+ ##### Properties
996
+
997
+ | Property | Returns | Description |
998
+ |----------|---------|-------------|
999
+ | `members` | `list` | List of `Person` instances (or raw IDs for non-person members). Fetches from `GET v1/groups/{id}/members`. |
1000
+ | `name` | `str` | Alias for `displayName` |
1001
+
1002
+ ##### Methods
1003
+
1004
+ | Method | Signature | Description |
1005
+ |--------|-----------|-------------|
1006
+ | `delete` | `() -> bool` | Deletes the group |
1007
+ | `add_member` | `(person: Person) -> bool` | Adds a person via PATCH |
1008
+ | `delete_member` | `(person: Person) -> bool` | Removes a person via PATCH |
1009
+
1010
+ ---
1011
+
1012
+ ### ApplicationServicesSettings
1013
+
1014
+ `@dataclass_json @dataclass` — lazy-loaded via `Person.applications` property.
1015
+
1016
+ ```python
1017
+ class ApplicationServicesSettings:
1018
+ person: wxcadm.Person
1019
+ ring_devices_for_click_to_dial: bool # ringDevicesForClickToDialCallsEnabled
1020
+ ring_devices_for_group_page: bool # ringDevicesForGroupPageEnabled
1021
+ ring_devices_for_call_park: bool # ringDevicesForCallParkEnabled
1022
+ browser_client_enabled: bool # browserClientEnabled
1023
+ desktop_client_enabled: bool # desktopClientEnabled
1024
+ tablet_client_enabled: bool # tabletClientEnabled
1025
+ mobile_client_enabled: bool # mobileClientEnabled
1026
+ available_line_count: int # availableLineCount
1027
+ browser_client_id: Optional[str] # browserClientId
1028
+ desktop_client_id: Optional[str] # desktopClientId
1029
+ ```
1030
+
1031
+ ##### Properties
1032
+
1033
+ | Property | Returns | Description |
1034
+ |----------|---------|-------------|
1035
+ | `line_assignments` | `Optional[ApplicationLineAssignments]` | Line assignments for the desktop client. `None` if desktop client not enabled. |
1036
+
1037
+ ##### Setter Methods
1038
+
1039
+ Each pushes a single-key payload to `PUT v1/people/{id}/features/applications`:
1040
+
1041
+ | Method | Parameter |
1042
+ |--------|-----------|
1043
+ | `set_ring_devices_for_click_to_dial(enabled: bool)` | `ringDevicesForClickToDialCallsEnabled` |
1044
+ | `set_ring_devices_for_group_page(enabled: bool)` | `ringDevicesForGroupPageEnabled` |
1045
+ | `set_ring_devices_for_call_park(enabled: bool)` | `ringDevicesForCallParkEnabled` |
1046
+ | `set_browser_client_enabled(enabled: bool)` | `browserClientEnabled` |
1047
+ | `set_desktop_client_enabled(enabled: bool)` | `desktopClientEnabled` |
1048
+ | `set_tablet_client_enabled(enabled: bool)` | `tabletClientEnabled` |
1049
+ | `set_mobile_client_enabled(enabled: bool)` | `mobileClientEnabled` |
1050
+
1051
+ ---
1052
+
1053
+ ### ApplicationLineAssignments / ApplicationLine
1054
+
1055
+ #### ApplicationLineAssignments
1056
+
1057
+ ```python
1058
+ class ApplicationLineAssignments:
1059
+ def __init__(self, person: wxcadm.Person, client_id: str)
1060
+ ```
1061
+
1062
+ Fetches from `GET v1/telephony/config/people/{id}/applications/{client_id}/members`.
1063
+
1064
+ | Attribute | Type | Description |
1065
+ |-----------|------|-------------|
1066
+ | `person` | `Person` | The owning person |
1067
+ | `client_id` | `str` | The application client ID |
1068
+ | `lines` | `list[ApplicationLine]` | The line assignments |
1069
+ | `model` | `str` | Application name |
1070
+ | `max_line_count` | `int` | Max device ports |
1071
+
1072
+ ##### Methods
1073
+
1074
+ | Method | Signature | Description |
1075
+ |--------|-----------|-------------|
1076
+ | `get` | `(line_owner: Person \| VirtualLine \| Workspace) -> Optional[ApplicationLine]` | Find the line for a given owner |
1077
+ | `add` | `(line_owner: Person \| VirtualLine \| Workspace) -> ApplicationLine` | Add a new line assignment. Added at next available port with defaults. |
1078
+
1079
+ #### ApplicationLine (dataclass)
1080
+
1081
+ `@dataclass_json @dataclass`
1082
+
1083
+ | Field | Type | API Field Name |
1084
+ |-------|------|---------------|
1085
+ | `port` | `int` | `port` |
1086
+ | `member_type` | `str` | `memberType` |
1087
+ | `id` | `str` | `id` |
1088
+ | `line_type` | `str` | `lineType` |
1089
+ | `primary_owner` | `bool` | `primaryOwner` |
1090
+ | `num_lines` | `int` | `lineWeight` |
1091
+ | `hotline_enabled` | `bool` | `hotlineEnabled` |
1092
+ | `allow_call_decline` | `bool` | `allowCallDeclineEnabled` |
1093
+ | `line_label` | `Optional[str]` | `lineLabel` |
1094
+ | `hotline_destination` | `Optional[bool]` | `hotlineDestination` |
1095
+ | `line_owner` | `Person \| Workspace \| VirtualLine \| None` | (resolved in `__post_init__`) |
1096
+
1097
+ `__post_init__` resolves `line_owner` by looking up the `id` in the appropriate org collection based on `member_type` (`PEOPLE`, `VIRTUAL_LINE`, `PLACE`).
1098
+
1099
+ ##### Methods
1100
+
1101
+ | Method | Signature | Description |
1102
+ |--------|-----------|-------------|
1103
+ | `set_hotline` | `(enabled: bool, destination: Optional[bool] = None) -> bool` | Enable/disable hotline. `destination` required when enabling. |
1104
+ | `set_call_decline` | `(enabled: bool) -> bool` | Enable/disable call decline across all endpoints |
1105
+ | `set_label` | `(label: str \| None) -> bool` | Set line label; `None` reverts to default |
1106
+ | `delete` | `() -> bool` | Remove this line assignment |
1107
+
1108
+ ---
1109
+
1110
+ ### SingleNumberReach / SnrNumber
1111
+
1112
+ #### SingleNumberReach
1113
+
1114
+ ```python
1115
+ @dataclass
1116
+ class SingleNumberReach:
1117
+ enabled: bool
1118
+ alert_all_for_click_to_dial: bool
1119
+ numbers: list[SnrNumber]
1120
+ person: wxcadm.Person
1121
+ ```
1122
+
1123
+ Accessed via `Person.single_number_reach` property.
1124
+
1125
+ ##### Class Methods
1126
+
1127
+ | Method | Signature | Description |
1128
+ |--------|-----------|-------------|
1129
+ | `from_api` | `(person: Person) -> SingleNumberReach` | Alternate constructor that fetches from API |
1130
+
1131
+ ##### Methods
1132
+
1133
+ | Method | Signature | Description |
1134
+ |--------|-----------|-------------|
1135
+ | `add_number` | `(phone_number: str, name: str, enabled: bool, do_not_forward_calls: bool = False, answer_confirmation: bool = False) -> SnrNumber` | Add a new SNR destination |
1136
+
1137
+ #### SnrNumber
1138
+
1139
+ `@dataclass_json @dataclass`
1140
+
1141
+ | Field | Type | API Field Name |
1142
+ |-------|------|---------------|
1143
+ | `id` | `Optional[str]` | `id` |
1144
+ | `phone_number` | `str` | `phoneNumber` |
1145
+ | `enabled` | `bool` | `enabled` |
1146
+ | `name` | `str` | `name` |
1147
+ | `do_not_forward_calls` | `bool` | `doNotForwardCallsEnabled` |
1148
+ | `answer_confirmation` | `bool` | `answerConfirmationEnabled` |
1149
+
1150
+ ##### Methods
1151
+
1152
+ | Method | Signature | Description |
1153
+ |--------|-----------|-------------|
1154
+ | `enable` | `() -> bool` | Enable this SNR number |
1155
+ | `disable` | `() -> bool` | Disable this SNR number |
1156
+ | `change_name` | `(name: str) -> bool` | Rename the SNR entry |
1157
+ | `set_answer_confirmation` | `(enabled: bool) -> bool` | Toggle answer confirmation |
1158
+ | `set_do_not_forward_calls` | `(enabled: bool) -> bool` | Toggle call forwarding prevention |
1159
+ | `delete` | `() -> bool` | Delete the SNR number |
1160
+
1161
+ > **Note:** In `set_do_not_forward_calls`, the source code sets `self.answer_confirmation = enabled` instead of `self.do_not_forward_calls = enabled` (line 2547 of person.py). This is a confirmed copy-paste bug — the API call itself sends the correct `doNotForwardCallsEnabled` payload, but the local instance attribute is stale after the call.
1162
+
1163
+ ---
1164
+
1165
+ ## Person Call Settings Coverage
1166
+
1167
+ wxcadm covers **19 of the ~34 person call settings** available through the Webex Calling API. The following settings are **not implemented in wxcadm** and require wxc_sdk or direct Webex REST API calls:
1168
+
1169
+ | Setting | Notes |
1170
+ |---------|-------|
1171
+ | Call Waiting | Not exposed |
1172
+ | Selective Call Forwarding (rules-based) | Not exposed |
1173
+ | Selective Call Acceptance | Not exposed |
1174
+ | Selective Call Rejection | Not exposed |
1175
+ | Anonymous Call Rejection (REST) | Available via XSI only (`person.xsi.anonymous_call_rejection`), not via REST API |
1176
+ | Sequential Ring | Not exposed |
1177
+ | Simultaneous Ring | Not exposed |
1178
+ | Priority Alert | Not exposed |
1179
+ | Incoming Call Notification | Not exposed |
1180
+ | Connected Line ID Restriction (COLR) | Not exposed |
1181
+ | Calling Line ID Restriction (CLIR) | Not exposed |
1182
+ | Music on Hold (person-level) | Not exposed |
1183
+ | Receptionist Client | Not exposed |
1184
+ | Call Bridge | Not exposed |
1185
+ | Agent Join/Unjoin (Call Queue specific) | Not exposed |
1186
+ | Executive settings (caller-side) | Executive Assistant is covered; the executive's own settings are not |
1187
+
1188
+ For the complete person settings surface, see the wxc_sdk person-call-settings docs linked in [See Also](#see-also) below.
1189
+
1190
+ ---
1191
+
1192
+ ## wxcadm vs wxc_sdk
1193
+
1194
+ ### Structural Differences
1195
+
1196
+ | Aspect | wxcadm | wxc_sdk |
1197
+ |--------|--------|---------|
1198
+ | **Person access** | `org.people.get(email=...)` returns `Person` with methods | `api.people.list(email=...)` returns data-only `Person` objects |
1199
+ | **Settings access** | Methods on the `Person` object: `person.get_vm_config()` | Separate API class: `api.person_settings.voicemail.read(person_id=...)` |
1200
+ | **Mutation pattern** | `person.push_vm_config(config)` — method on the instance | `api.person_settings.voicemail.configure(person_id=..., settings=...)` |
1201
+ | **Lazy loading** | Settings dicts start empty; populated by `get_*()` calls | No state caching; every call hits the API |
1202
+ | **Data models** | Mix of raw dicts and dataclasses (`BargeInSettings`, `ApplicationServicesSettings`, `SingleNumberReach`) | Strongly typed Pydantic models for everything |
1203
+ | **List behavior** | `PersonList` extends `UserList` with smart caching + filter memory | Returns plain lists; pagination handled internally |
1204
+
1205
+ ### Feature Coverage Comparison
1206
+
1207
+ | Feature | wxcadm Person | wxc_sdk Equivalent |
1208
+ |---------|--------------|-------------------|
1209
+ | User CRUD | `PersonList.create()`, `Person.delete()`, `Person.update_person()` | `PeopleApi.create()`, `.delete()`, `.update()` |
1210
+ | License management | `assign_wxc()`, `unassign_wxc()`, `set_calling_only()` | Manual via `PeopleApi.update()` |
1211
+ | Voicemail greeting upload | `upload_busy_greeting()`, `upload_no_answer_greeting()` | `VoicemailApi.configure_busy_greeting()` / `.configure_no_answer_greeting()` |
1212
+ | Caller ID (friendly) | `set_caller_id(name, number)` with keyword shortcuts | Must build payload manually for `PersonSettingsApi.caller_id.configure()` |
1213
+ | Call recording (friendly) | `enable_call_recording(type=..., transcribe=..., ai_summary=...)` | Must build `CallRecordingSetting` model manually |
1214
+ | XSI session | `start_xsi()` — built-in XSI integration | Not available |
1215
+ | Spark ID decode | `spark_id` property (base64 decode) | Not available |
1216
+ | ECBN management | `ecbn` property, `set_ecbn()`, `ecbn_null_change()` | `PersonSettingsApi.ecbn` (`ECBNApi`) |
1217
+ | Single Number Reach | `single_number_reach` property with full `SnrNumber` management | `PersonSettingsApi.single_number_reach` (`SingleNumberReachApi`) |
1218
+ | Application line assignments | `ApplicationLineAssignments` with add/remove/configure | `PersonSettingsApi.app_shared_line` (`AppSharedLineApi`) — has `search_members()`, `get_members()`, `update_members()` |
1219
+ | Hunt Group / Call Queue membership | `hunt_groups`, `call_queues` properties (reverse lookup) | Must query `HuntGroupApi` / `CallQueueApi` directly |
1220
+ | Monitoring (who monitors whom) | `monitoring` property, `get_monitored_by()` | `PersonSettingsApi.monitoring` |
1221
+ | User Groups | `UserGroups`/`UserGroup` classes with CRUD | `GroupsApi` (at `api.groups`) — list, create, get, update, delete, members |
1222
+ | Voice Messages (Me scope) | `Me.get_voice_messages()`, `Me.voicemail_summary` | `TelephonyApi.voice_messaging` (`VoiceMessagingApi`) — `.summary()`, `.list()`, `.delete()`, `.mark_as_read()`, `.mark_as_unread()` |
1223
+
1224
+ ### wxcadm-Unique Capabilities
1225
+
1226
+ These features have no direct wxc_sdk equivalent or are significantly more convenient in wxcadm:
1227
+
1228
+ 1. **`set_caller_id(name, number)`** — keyword-based shortcuts (`"direct"`, `"location"`, or custom) instead of building the raw payload
1229
+ 2. **`enable_call_recording(...)`** — single method with all recording parameters including AI transcription/summary flags
1230
+ 3. **`set_calling_only()`** — one-call license cleanup that intelligently keeps screen share
1231
+ 4. **`ecbn_null_change()`** — backend bug workaround not present in wxc_sdk
1232
+ 5. **`spark_id`** — decoded internal identifier
1233
+ 6. **`start_xsi()`** — integrated XSI session management
1234
+ 7. **`get_full_config()`** — batch fetch of all person settings
1235
+ 8. **`PersonList` filter memory** — `refresh()` re-runs with the same filters
1236
+ 9. **Reverse hunt group/call queue lookups** — `person.hunt_groups` and `person.call_queues` search the org
1237
+ 10. **`ApplicationLineAssignments`** — manages shared call appearances on the desktop client with `add()`, line labels, hotline, and call decline settings
1238
+
1239
+ ---
1240
+
1241
+ ## Gotchas
1242
+
1243
+ - **`role_names()` returns only the first role.** The source code has `return roles` inside the `for` loop (line 483 of person.py), so it exits after resolving the first role ID instead of collecting all of them.
1244
+ - **`SnrNumber.set_do_not_forward_calls()` has a confirmed copy-paste bug.** The method sets `self.answer_confirmation = enabled` instead of `self.do_not_forward_calls = enabled` on the local instance (line 2547 of person.py). The API payload is correct, but the local state is stale after the call.
1245
+ - **Reverse group lookups are slow on large orgs.** `person.hunt_groups` and `person.call_queues` iterate every hunt group/call queue in the org and check each agent list. On orgs with many groups, this generates significant API traffic.
1246
+ - **`push_call_recording()` silently strips Dubber keys.** The method removes `serviceProvider`, `externalGroup`, and `externalIdentifier` before PUT, since the API rejects them. If you build a config dict from a GET response and push it back, this is handled automatically, but be aware the round-trip is not lossless.
1247
+ - **wxc_sdk equivalents have been verified and corrected.** Key corrections: voicemail greeting upload uses `VoicemailApi.configure_busy_greeting()` / `.configure_no_answer_greeting()`; application line assignments use `AppSharedLineApi` (not "not exposed"); groups use `GroupsApi` (not `GroupApi`); voice messages use `TelephonyApi.voice_messaging` (not `.voicemail`).
1248
+ - **`get_full_config()` returns `False` silently for non-WxC users.** If you call it on a person without a Webex Calling license, it returns `False` instead of raising an exception. Check the return value or verify `person.wxc` first.
1249
+
1250
+ ## See Also
1251
+
1252
+ - [person-call-settings-handling.md](person-call-settings-handling.md) — wxc_sdk call handling settings (forwarding, call waiting, sequential ring, simultaneous ring, selective forwarding/acceptance/rejection)
1253
+ - [person-call-settings-media.md](person-call-settings-media.md) — wxc_sdk media and recording settings (call recording, voicemail, music on hold)
1254
+ - [person-call-settings-permissions.md](person-call-settings-permissions.md) — wxc_sdk permissions and screening settings (outgoing permission, incoming permission, caller ID, anonymous call rejection)
1255
+ - [person-call-settings-behavior.md](person-call-settings-behavior.md) — wxc_sdk behavior and presence settings (calling behavior, DND, hoteling, barge-in, push-to-talk)