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.
- wxcli/__init__.py +4 -0
- wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
- wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
- wxcli/_playbook/.claude/rules/cleanup.md +29 -0
- wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
- wxcli/_playbook/.claude/rules/org-health.md +14 -0
- wxcli/_playbook/.claude/settings.json +8 -0
- wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
- wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
- wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
- wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
- wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
- wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
- wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
- wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
- wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
- wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
- wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
- wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
- wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
- wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
- wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
- wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
- wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
- wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
- wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
- wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
- wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
- wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
- wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
- wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
- wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
- wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
- wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
- wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
- wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
- wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
- wxcli/_playbook/CLAUDE.md +373 -0
- wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
- wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
- wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
- wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
- wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
- wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
- wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
- wxcli/_playbook/docs/reference/admin-partner.md +357 -0
- wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
- wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
- wxcli/_playbook/docs/reference/authentication.md +965 -0
- wxcli/_playbook/docs/reference/call-control.md +1205 -0
- wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
- wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
- wxcli/_playbook/docs/reference/call-routing.md +2304 -0
- wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
- wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
- wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
- wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
- wxcli/_playbook/docs/reference/devices-core.md +1869 -0
- wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
- wxcli/_playbook/docs/reference/devices-platform.md +467 -0
- wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
- wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
- wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
- wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
- wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
- wxcli/_playbook/docs/reference/meetings-content.md +473 -0
- wxcli/_playbook/docs/reference/meetings-core.md +903 -0
- wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
- wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
- wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
- wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
- wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
- wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
- wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
- wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
- wxcli/_playbook/docs/reference/provisioning.md +1366 -0
- wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
- wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
- wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
- wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
- wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
- wxcli/_version.py +24 -0
- wxcli/auth.py +137 -0
- wxcli/commands/__init__.py +0 -0
- wxcli/commands/_registry.py +181 -0
- wxcli/commands/activation_email.py +103 -0
- wxcli/commands/admin_recordings.py +585 -0
- wxcli/commands/analytics.py +105 -0
- wxcli/commands/announcement_playlists.py +219 -0
- wxcli/commands/announcements.py +519 -0
- wxcli/commands/archive_users.py +36 -0
- wxcli/commands/attachment_actions.py +60 -0
- wxcli/commands/audit_events.py +83 -0
- wxcli/commands/authorizations.py +113 -0
- wxcli/commands/auto_attendant.py +642 -0
- wxcli/commands/broadworks_billing_reports.py +126 -0
- wxcli/commands/broadworks_enterprises.py +160 -0
- wxcli/commands/broadworks_subscribers.py +319 -0
- wxcli/commands/broadworks_workspaces.py +108 -0
- wxcli/commands/call_controls.py +1304 -0
- wxcli/commands/call_park.py +494 -0
- wxcli/commands/call_pickup.py +229 -0
- wxcli/commands/call_queue.py +1878 -0
- wxcli/commands/call_recording.py +707 -0
- wxcli/commands/call_routing.py +1610 -0
- wxcli/commands/call_settings_for_me_phase_5.py +212 -0
- wxcli/commands/caller_reputation.py +169 -0
- wxcli/commands/calling_service.py +305 -0
- wxcli/commands/cc_address_book.py +770 -0
- wxcli/commands/cc_agent_greetings.py +242 -0
- wxcli/commands/cc_agent_summaries.py +39 -0
- wxcli/commands/cc_agent_wellbeing.py +216 -0
- wxcli/commands/cc_agents.py +425 -0
- wxcli/commands/cc_ai_assistant.py +55 -0
- wxcli/commands/cc_ai_feature.py +294 -0
- wxcli/commands/cc_audio_files.py +149 -0
- wxcli/commands/cc_auto_csat.py +311 -0
- wxcli/commands/cc_aux_code.py +458 -0
- wxcli/commands/cc_business_hour.py +353 -0
- wxcli/commands/cc_call_monitoring.py +228 -0
- wxcli/commands/cc_callbacks.py +194 -0
- wxcli/commands/cc_campaign.py +212 -0
- wxcli/commands/cc_captures.py +39 -0
- wxcli/commands/cc_contact_list.py +169 -0
- wxcli/commands/cc_contact_number.py +295 -0
- wxcli/commands/cc_data_sources.py +235 -0
- wxcli/commands/cc_desktop_layout.py +380 -0
- wxcli/commands/cc_desktop_profile.py +322 -0
- wxcli/commands/cc_dial_number.py +511 -0
- wxcli/commands/cc_dial_plan.py +347 -0
- wxcli/commands/cc_dnc.py +101 -0
- wxcli/commands/cc_entry_point.py +545 -0
- wxcli/commands/cc_ewt.py +51 -0
- wxcli/commands/cc_flow.py +477 -0
- wxcli/commands/cc_global_vars.py +430 -0
- wxcli/commands/cc_holiday_list.py +335 -0
- wxcli/commands/cc_journey.py +1261 -0
- wxcli/commands/cc_legacy_flows.py +49 -0
- wxcli/commands/cc_multimedia_profile.py +436 -0
- wxcli/commands/cc_notification.py +51 -0
- wxcli/commands/cc_outdial_ani.py +604 -0
- wxcli/commands/cc_overrides.py +341 -0
- wxcli/commands/cc_queue.py +1083 -0
- wxcli/commands/cc_queue_stats.py +55 -0
- wxcli/commands/cc_realtime.py +51 -0
- wxcli/commands/cc_resource_collection.py +312 -0
- wxcli/commands/cc_search.py +46 -0
- wxcli/commands/cc_site.py +400 -0
- wxcli/commands/cc_skill.py +350 -0
- wxcli/commands/cc_skill_profile.py +289 -0
- wxcli/commands/cc_subscriptions.py +426 -0
- wxcli/commands/cc_summaries.py +130 -0
- wxcli/commands/cc_tasks.py +844 -0
- wxcli/commands/cc_team.py +325 -0
- wxcli/commands/cc_user_profiles.py +349 -0
- wxcli/commands/cc_users.py +701 -0
- wxcli/commands/cc_work_types.py +363 -0
- wxcli/commands/cdr.py +89 -0
- wxcli/commands/classifications.py +38 -0
- wxcli/commands/cleanup.py +1427 -0
- wxcli/commands/client_settings.py +72 -0
- wxcli/commands/conference.py +328 -0
- wxcli/commands/configure.py +72 -0
- wxcli/commands/converged_recordings.py +347 -0
- wxcli/commands/converged_recordings_export.py +310 -0
- wxcli/commands/cq_playlists.py +42 -0
- wxcli/commands/cucm.py +2794 -0
- wxcli/commands/cucm_config.py +129 -0
- wxcli/commands/customer_assist.py +373 -0
- wxcli/commands/data_sources.py +227 -0
- wxcli/commands/dect_devices.py +787 -0
- wxcli/commands/device_configurations.py +77 -0
- wxcli/commands/device_dynamic_settings.py +320 -0
- wxcli/commands/device_settings.py +1489 -0
- wxcli/commands/devices.py +280 -0
- wxcli/commands/domains.py +142 -0
- wxcli/commands/ecm.py +178 -0
- wxcli/commands/emergency_services.py +827 -0
- wxcli/commands/events.py +83 -0
- wxcli/commands/external_voicemail.py +52 -0
- wxcli/commands/groups.py +206 -0
- wxcli/commands/guest_management.py +76 -0
- wxcli/commands/hds.py +340 -0
- wxcli/commands/hot_desk.py +67 -0
- wxcli/commands/hot_desking_members.py +118 -0
- wxcli/commands/hot_desking_portal.py +124 -0
- wxcli/commands/hunt_group.py +577 -0
- wxcli/commands/hybrid_clusters.py +71 -0
- wxcli/commands/hybrid_connectors.py +67 -0
- wxcli/commands/identity_org.py +159 -0
- wxcli/commands/init_playbook.py +155 -0
- wxcli/commands/licenses.py +106 -0
- wxcli/commands/live_monitoring.py +40 -0
- wxcli/commands/location_call_handling.py +577 -0
- wxcli/commands/location_schedules.py +341 -0
- wxcli/commands/location_settings.py +1297 -0
- wxcli/commands/location_voicemail.py +494 -0
- wxcli/commands/locations.py +336 -0
- wxcli/commands/meeting_captions.py +110 -0
- wxcli/commands/meeting_chats.py +63 -0
- wxcli/commands/meeting_invitees.py +234 -0
- wxcli/commands/meeting_messages.py +28 -0
- wxcli/commands/meeting_participants.py +278 -0
- wxcli/commands/meeting_polls.py +111 -0
- wxcli/commands/meeting_preferences.py +515 -0
- wxcli/commands/meeting_qa.py +78 -0
- wxcli/commands/meeting_qualities.py +43 -0
- wxcli/commands/meeting_reports.py +101 -0
- wxcli/commands/meeting_session_types.py +105 -0
- wxcli/commands/meeting_site.py +57 -0
- wxcli/commands/meeting_slido.py +44 -0
- wxcli/commands/meeting_summaries.py +92 -0
- wxcli/commands/meeting_tracking_codes.py +233 -0
- wxcli/commands/meeting_transcripts.py +230 -0
- wxcli/commands/meetings.py +1997 -0
- wxcli/commands/memberships.py +164 -0
- wxcli/commands/messages.py +213 -0
- wxcli/commands/mode_management.py +244 -0
- wxcli/commands/my_call_settings.py +3577 -0
- wxcli/commands/numbers.py +405 -0
- wxcli/commands/operating_modes.py +410 -0
- wxcli/commands/org_contacts.py +284 -0
- wxcli/commands/org_health_cli.py +55 -0
- wxcli/commands/org_settings.py +71 -0
- wxcli/commands/organizations.py +83 -0
- wxcli/commands/paging_group.py +257 -0
- wxcli/commands/partner_admins.py +141 -0
- wxcli/commands/partner_reports.py +188 -0
- wxcli/commands/partner_tags.py +216 -0
- wxcli/commands/people.py +279 -0
- wxcli/commands/person_call_settings.py +71 -0
- wxcli/commands/pstn.py +280 -0
- wxcli/commands/recording_report.py +154 -0
- wxcli/commands/report_templates.py +38 -0
- wxcli/commands/reports.py +144 -0
- wxcli/commands/resource_group_memberships.py +160 -0
- wxcli/commands/resource_groups.py +67 -0
- wxcli/commands/roles.py +63 -0
- wxcli/commands/room_tabs.py +160 -0
- wxcli/commands/rooms.py +225 -0
- wxcli/commands/scim_bulk.py +46 -0
- wxcli/commands/scim_groups.py +246 -0
- wxcli/commands/scim_schemas.py +82 -0
- wxcli/commands/scim_users.py +283 -0
- wxcli/commands/security_audit.py +54 -0
- wxcli/commands/service_apps.py +51 -0
- wxcli/commands/single_number_reach.py +209 -0
- wxcli/commands/team_memberships.py +155 -0
- wxcli/commands/teams.py +153 -0
- wxcli/commands/ucm_profile.py +42 -0
- wxcli/commands/update.py +219 -0
- wxcli/commands/user_settings.py +5116 -0
- wxcli/commands/video_mesh.py +1090 -0
- wxcli/commands/virtual_extensions.py +502 -0
- wxcli/commands/virtual_line_settings.py +2072 -0
- wxcli/commands/webhooks.py +176 -0
- wxcli/commands/wholesale_billing_reports.py +147 -0
- wxcli/commands/wholesale_provisioning.py +523 -0
- wxcli/commands/workspace_locations.py +339 -0
- wxcli/commands/workspace_metrics.py +103 -0
- wxcli/commands/workspace_personalization.py +70 -0
- wxcli/commands/workspace_settings.py +3347 -0
- wxcli/commands/workspaces.py +279 -0
- wxcli/commands/xapi.py +114 -0
- wxcli/config.py +139 -0
- wxcli/errors.py +77 -0
- wxcli/main.py +210 -0
- wxcli/migration/CLAUDE.md +106 -0
- wxcli/migration/__init__.py +1 -0
- wxcli/migration/advisory/CLAUDE.md +196 -0
- wxcli/migration/advisory/__init__.py +46 -0
- wxcli/migration/advisory/advisor.py +107 -0
- wxcli/migration/advisory/advisory_patterns.py +2552 -0
- wxcli/migration/advisory/recommendation_rules.py +835 -0
- wxcli/migration/cucm/CLAUDE.md +74 -0
- wxcli/migration/cucm/__init__.py +5 -0
- wxcli/migration/cucm/connection.py +265 -0
- wxcli/migration/cucm/discovery.py +225 -0
- wxcli/migration/cucm/extractors/__init__.py +1 -0
- wxcli/migration/cucm/extractors/announcements.py +92 -0
- wxcli/migration/cucm/extractors/base.py +90 -0
- wxcli/migration/cucm/extractors/device_profiles.py +98 -0
- wxcli/migration/cucm/extractors/devices.py +193 -0
- wxcli/migration/cucm/extractors/e911.py +103 -0
- wxcli/migration/cucm/extractors/features.py +309 -0
- wxcli/migration/cucm/extractors/helpers.py +73 -0
- wxcli/migration/cucm/extractors/informational.py +295 -0
- wxcli/migration/cucm/extractors/locations.py +221 -0
- wxcli/migration/cucm/extractors/moh.py +100 -0
- wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
- wxcli/migration/cucm/extractors/routing.py +493 -0
- wxcli/migration/cucm/extractors/shared_lines.py +146 -0
- wxcli/migration/cucm/extractors/templates.py +229 -0
- wxcli/migration/cucm/extractors/tier4.py +173 -0
- wxcli/migration/cucm/extractors/users.py +240 -0
- wxcli/migration/cucm/extractors/voicemail.py +243 -0
- wxcli/migration/cucm/extractors/workspaces.py +88 -0
- wxcli/migration/cucm/unity_connection.py +304 -0
- wxcli/migration/execute/CLAUDE.md +372 -0
- wxcli/migration/execute/__init__.py +303 -0
- wxcli/migration/execute/batch.py +277 -0
- wxcli/migration/execute/dependency.py +483 -0
- wxcli/migration/execute/engine.py +964 -0
- wxcli/migration/execute/handlers.py +2232 -0
- wxcli/migration/execute/planner.py +1939 -0
- wxcli/migration/execute/runtime.py +571 -0
- wxcli/migration/export/CLAUDE.md +49 -0
- wxcli/migration/export/__init__.py +8 -0
- wxcli/migration/export/csv_export.py +126 -0
- wxcli/migration/export/deployment_plan.py +479 -0
- wxcli/migration/export/json_export.py +60 -0
- wxcli/migration/models.py +941 -0
- wxcli/migration/phone_models.py +50 -0
- wxcli/migration/preflight/CLAUDE.md +52 -0
- wxcli/migration/preflight/__init__.py +89 -0
- wxcli/migration/preflight/checks.py +911 -0
- wxcli/migration/preflight/runner.py +293 -0
- wxcli/migration/rate_limiter.py +144 -0
- wxcli/migration/report/CLAUDE.md +245 -0
- wxcli/migration/report/__init__.py +7 -0
- wxcli/migration/report/appendix.py +2437 -0
- wxcli/migration/report/assembler.py +183 -0
- wxcli/migration/report/charts.py +263 -0
- wxcli/migration/report/executive.py +776 -0
- wxcli/migration/report/explainer.py +704 -0
- wxcli/migration/report/helpers.py +74 -0
- wxcli/migration/report/ingest.py +152 -0
- wxcli/migration/report/notice_templates.py +192 -0
- wxcli/migration/report/score.py +375 -0
- wxcli/migration/report/styles.py +1052 -0
- wxcli/migration/report/user_diff.py +1052 -0
- wxcli/migration/report/user_notice.py +425 -0
- wxcli/migration/state.py +139 -0
- wxcli/migration/store.py +860 -0
- wxcli/migration/transform/CLAUDE.md +107 -0
- wxcli/migration/transform/__init__.py +12 -0
- wxcli/migration/transform/analysis_pipeline.py +453 -0
- wxcli/migration/transform/analyzers/__init__.py +142 -0
- wxcli/migration/transform/analyzers/css_permission.py +189 -0
- wxcli/migration/transform/analyzers/css_routing.py +335 -0
- wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
- wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
- wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
- wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
- wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
- wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
- wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
- wxcli/migration/transform/analyzers/missing_data.py +300 -0
- wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
- wxcli/migration/transform/analyzers/shared_line.py +170 -0
- wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
- wxcli/migration/transform/analyzers/workspace_license.py +212 -0
- wxcli/migration/transform/cross_reference.py +1136 -0
- wxcli/migration/transform/cucm_pattern.py +246 -0
- wxcli/migration/transform/decisions.py +301 -0
- wxcli/migration/transform/e164.py +145 -0
- wxcli/migration/transform/engine.py +256 -0
- wxcli/migration/transform/mappers/CLAUDE.md +123 -0
- wxcli/migration/transform/mappers/__init__.py +76 -0
- wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
- wxcli/migration/transform/mappers/base.py +190 -0
- wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
- wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
- wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
- wxcli/migration/transform/mappers/css_mapper.py +868 -0
- wxcli/migration/transform/mappers/dect_mapper.py +367 -0
- wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
- wxcli/migration/transform/mappers/device_mapper.py +227 -0
- wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
- wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
- wxcli/migration/transform/mappers/e911_mapper.py +129 -0
- wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
- wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
- wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
- wxcli/migration/transform/mappers/line_mapper.py +310 -0
- wxcli/migration/transform/mappers/location_mapper.py +235 -0
- wxcli/migration/transform/mappers/moh_mapper.py +114 -0
- wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
- wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
- wxcli/migration/transform/mappers/routing_mapper.py +821 -0
- wxcli/migration/transform/mappers/snr_mapper.py +201 -0
- wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
- wxcli/migration/transform/mappers/user_mapper.py +264 -0
- wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
- wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
- wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
- wxcli/migration/transform/normalizers.py +2008 -0
- wxcli/migration/transform/pattern_converter.py +106 -0
- wxcli/migration/transform/pipeline.py +271 -0
- wxcli/migration/transform/rules.py +255 -0
- wxcli/org_health/CLAUDE.md +63 -0
- wxcli/org_health/__init__.py +7 -0
- wxcli/org_health/analyze.py +93 -0
- wxcli/org_health/checks.py +458 -0
- wxcli/org_health/collector.py +62 -0
- wxcli/org_health/models.py +78 -0
- wxcli/org_health/report.py +300 -0
- wxcli/output.py +101 -0
- wxcli-1.2.0.dist-info/METADATA +505 -0
- wxcli-1.2.0.dist-info/RECORD +413 -0
- wxcli-1.2.0.dist-info/WHEEL +5 -0
- wxcli-1.2.0.dist-info/entry_points.txt +2 -0
- wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
- wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
- wxcli-1.2.0.dist-info/scm_version.json +8 -0
- 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`
|