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,1305 @@
|
|
|
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. DeviceList(org, parent) signature, Device.calling_id property, DeviceMember.esn/routing_prefix/location_id, VirtualLine.name, Workspace.unassign_wxc(), WorkspaceLocation removal — all accurately documented. No discrepancies found. -->
|
|
3
|
+
# wxcadm: Devices, DECT, Workspaces & Virtual Lines
|
|
4
|
+
|
|
5
|
+
Reference for device management, DECT networks, workspaces, virtual lines, and number management in wxcadm.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
10
|
+
## When to Use wxcadm vs Raw HTTP
|
|
11
|
+
|
|
12
|
+
| Use wxcadm when | Use raw HTTP when |
|
|
13
|
+
|---|---|
|
|
14
|
+
| Device activation workflows (activation code generation, SIP credential retrieval) | Standard device/workspace/virtual line CRUD (list, get, create, update, delete) |
|
|
15
|
+
| Object-graph navigation (org -> location -> workspace -> device -> members) without tracking IDs manually | You already have the resource IDs and need a targeted API call |
|
|
16
|
+
| Bulk operations that benefit from stateful `DeviceList`/`WorkspaceList` filtering (e.g., `webex_calling()`, `get_by_status()`) | Single-resource reads or writes where the SDK wrapper adds no value |
|
|
17
|
+
|
|
18
|
+
> **Note:** The playbook uses raw HTTP via `api.session.rest_*()` for standard CRUD operations. wxcadm is only needed here for its device activation workflow convenience and stateful object-graph navigation.
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Table of Contents
|
|
23
|
+
|
|
24
|
+
1. [Device Class](#device-class)
|
|
25
|
+
2. [Device Members & Layout](#device-members--layout)
|
|
26
|
+
3. [DECT Networks](#dect-networks)
|
|
27
|
+
4. [Workspace Class](#workspace-class)
|
|
28
|
+
5. [Virtual Lines](#virtual-lines)
|
|
29
|
+
6. [Number Management](#number-management)
|
|
30
|
+
7. [wxcadm vs wxc_sdk](#wxcadm-vs-wxc_sdk)
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Device Class
|
|
35
|
+
|
|
36
|
+
Source: `wxcadm/device.py`
|
|
37
|
+
|
|
38
|
+
### Access Patterns
|
|
39
|
+
|
|
40
|
+
Devices can be accessed from three scopes:
|
|
41
|
+
|
|
42
|
+
```python
|
|
43
|
+
# Org-level — all devices in the org
|
|
44
|
+
all_devices = org.devices
|
|
45
|
+
|
|
46
|
+
# Person-level — devices for a specific person
|
|
47
|
+
person_devices = person.devices
|
|
48
|
+
|
|
49
|
+
# Workspace-level — devices for a specific workspace
|
|
50
|
+
ws_devices = workspace.devices
|
|
51
|
+
|
|
52
|
+
# Location-level — devices at a location
|
|
53
|
+
loc_devices = DeviceList(org, parent=location)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
All return a `DeviceList` (subclass of `UserList`).
|
|
57
|
+
|
|
58
|
+
### DeviceList Methods
|
|
59
|
+
|
|
60
|
+
#### `DeviceList.get(...)`
|
|
61
|
+
|
|
62
|
+
Find a device by various criteria. Returns a single `Device` or `None` (except `connection_status`, which returns a list).
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
DeviceList.get(
|
|
66
|
+
id: Optional[str] = None,
|
|
67
|
+
name: Optional[str] = None, # Case-insensitive
|
|
68
|
+
mac_address: Optional[str] = None, # Accepts colons, dashes, or raw
|
|
69
|
+
spark_id: Optional[str] = None,
|
|
70
|
+
connection_status: Optional[str] = None # Returns a list
|
|
71
|
+
) -> Optional[Device]
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
device = org.devices.get(mac_address="AA:BB:CC:DD:EE:FF")
|
|
76
|
+
device = org.devices.get(name="Lobby Phone")
|
|
77
|
+
disconnected = org.devices.get(connection_status="disconnected")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
#### `DeviceList.create(...)`
|
|
81
|
+
|
|
82
|
+
Add a new device. Requires a `SupportedDevice` model reference.
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
DeviceList.create(
|
|
86
|
+
model: SupportedDevice,
|
|
87
|
+
mac: Optional[str] = None, # Omit to generate activation code
|
|
88
|
+
password: Optional[str] = None, # For non-Cisco-managed devices
|
|
89
|
+
person: Optional[Person] = None, # Required when DeviceList is Org-level
|
|
90
|
+
workspace: Optional[Workspace] = None # Required when DeviceList is Org-level
|
|
91
|
+
) -> dict
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Return value varies by device type:
|
|
95
|
+
|
|
96
|
+
| Scenario | Keys in returned dict |
|
|
97
|
+
|---|---|
|
|
98
|
+
| Activation code (no MAC) | `device_id`, `activation_code` |
|
|
99
|
+
| MAC-based, Cisco-managed | `device_id`, `mac`, `device_object` |
|
|
100
|
+
| MAC-based, partner/customer-managed | `device_id`, `mac`, `device_object`, `sip_auth_user`, `line_port`, `password`, `sip_userpart`, `sip_hostpart`, `sip_outbound_proxy`, `sip_outbound_proxy_srv` |
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
# Get a supported device model
|
|
104
|
+
model_8865 = org.devices.supported_devices.get("Cisco 8865")
|
|
105
|
+
|
|
106
|
+
# Create with activation code
|
|
107
|
+
result = workspace.devices.create(model=model_8865)
|
|
108
|
+
print(result['activation_code'])
|
|
109
|
+
|
|
110
|
+
# Create with MAC
|
|
111
|
+
result = workspace.devices.create(
|
|
112
|
+
model=model_8865,
|
|
113
|
+
mac="AABBCCDDEEFF"
|
|
114
|
+
)
|
|
115
|
+
print(result['device_id'])
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**Scope note:** Your token needs `identity:placeonetimepassword_create` to generate activation codes.
|
|
119
|
+
|
|
120
|
+
#### `DeviceList.refresh()`
|
|
121
|
+
|
|
122
|
+
Re-fetches the device list from Webex.
|
|
123
|
+
|
|
124
|
+
#### `DeviceList.webex_calling(enabled=True)`
|
|
125
|
+
|
|
126
|
+
Filter to devices with Webex Calling enabled or disabled.
|
|
127
|
+
|
|
128
|
+
```python
|
|
129
|
+
wxc_devices = org.devices.webex_calling()
|
|
130
|
+
non_wxc = org.devices.webex_calling(enabled=False)
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
#### `DeviceList.get_by_status(status: str)`
|
|
134
|
+
|
|
135
|
+
Filter devices by connection status. Accepts raw API values plus grouping shortcuts:
|
|
136
|
+
|
|
137
|
+
| Value | Matches |
|
|
138
|
+
|---|---|
|
|
139
|
+
| `"online"` | `connected`, `connected_with_issues` |
|
|
140
|
+
| `"offline"` | `disconnected`, `offline_expired`, `offline_deep_sleep` |
|
|
141
|
+
| `"connected"` | Exact match |
|
|
142
|
+
| `"disconnected"` | Exact match |
|
|
143
|
+
| `"activating"` | Exact match |
|
|
144
|
+
| `"unknown"` | Exact match |
|
|
145
|
+
|
|
146
|
+
```python
|
|
147
|
+
offline_devices = org.devices.get_by_status("offline")
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Device Attributes
|
|
151
|
+
|
|
152
|
+
| Attribute | Type | Description |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| `id` | `str` | Device ID |
|
|
155
|
+
| `model` | `str` | Model name (e.g. `"DMS Cisco 8865"`) |
|
|
156
|
+
| `mac` | `str` | MAC address (uppercase, no delimiters) |
|
|
157
|
+
| `display_name` | `str` | Display name in Webex |
|
|
158
|
+
| `ip_address` | `str` | Device IP |
|
|
159
|
+
| `activation_state` | `str` | Activation state |
|
|
160
|
+
| `type` | `str` | Type of device association |
|
|
161
|
+
| `is_owner` | `bool` | Whether parent is primary owner |
|
|
162
|
+
| `connection_status` | `str` | Online/offline status |
|
|
163
|
+
| `serial` | `str` | Serial number |
|
|
164
|
+
| `software` | `str` | OS/firmware version |
|
|
165
|
+
| `upgrade_channel` | `str` | Assigned upgrade channel |
|
|
166
|
+
| `tags` | `list` | Device tags |
|
|
167
|
+
| `capabilities` | `list` | Device capabilities |
|
|
168
|
+
| `user_permissions` | `list` | User permissions (e.g. `"xapi"`) |
|
|
169
|
+
| `owner` | `Person\|Workspace\|None` | Resolved primary owner |
|
|
170
|
+
| `location_id` | `str` | Location ID |
|
|
171
|
+
| `created` | `str` | Creation timestamp |
|
|
172
|
+
| `first_seen` | `str` | First online timestamp |
|
|
173
|
+
| `last_seen` | `str` | Last online timestamp |
|
|
174
|
+
|
|
175
|
+
### Device Properties & Methods
|
|
176
|
+
|
|
177
|
+
#### `Device.calling_id` (property)
|
|
178
|
+
|
|
179
|
+
The telephony-side device ID. Used internally for `/v1/telephony/config/devices/` API calls. Fetched lazily from the telephony config endpoint if not present in the device record.
|
|
180
|
+
|
|
181
|
+
#### `Device.config` (property)
|
|
182
|
+
|
|
183
|
+
Returns the full telephony device configuration as a dict.
|
|
184
|
+
|
|
185
|
+
#### `Device.settings` (property, settable)
|
|
186
|
+
|
|
187
|
+
Read or write the device settings. The structure varies by device model -- the raw dict from Webex is returned.
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
# Read
|
|
191
|
+
settings = device.settings
|
|
192
|
+
|
|
193
|
+
# Write
|
|
194
|
+
device.settings = updated_settings_dict
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
#### `Device.layout` (property)
|
|
198
|
+
|
|
199
|
+
Returns the `DeviceLayout` for the device. See [DeviceLayout](#devicelayout) below.
|
|
200
|
+
|
|
201
|
+
#### `Device.members` (property)
|
|
202
|
+
|
|
203
|
+
Returns a `DeviceMemberList` of configured lines on the device. See [Device Members](#device-members--layout).
|
|
204
|
+
|
|
205
|
+
#### `Device.apply_changes() -> bool`
|
|
206
|
+
|
|
207
|
+
Issues a request to the device to download and apply configuration changes.
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
device.apply_changes()
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
#### `Device.delete() -> bool`
|
|
214
|
+
|
|
215
|
+
Deletes the device from Webex Calling and Control Hub entirely.
|
|
216
|
+
|
|
217
|
+
#### `Device.change_tags(operation, tag=None)`
|
|
218
|
+
|
|
219
|
+
Modify the device tags.
|
|
220
|
+
|
|
221
|
+
```python
|
|
222
|
+
Device.change_tags(
|
|
223
|
+
operation: str, # "add", "remove", or "replace"
|
|
224
|
+
tag: Optional[str | list] = None
|
|
225
|
+
) -> bool
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
```python
|
|
229
|
+
device.change_tags("add", "floor-3")
|
|
230
|
+
device.change_tags("replace", ["lobby", "reception"])
|
|
231
|
+
device.change_tags("remove")
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### SupportedDevice & SupportedDeviceList
|
|
235
|
+
|
|
236
|
+
`SupportedDeviceList` enumerates all device models Webex supports. Access via:
|
|
237
|
+
|
|
238
|
+
```python
|
|
239
|
+
supported = org.devices.supported_devices
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
#### `SupportedDeviceList.get(model_name: str)`
|
|
243
|
+
|
|
244
|
+
Partial, case-insensitive match. Returns a single `SupportedDevice` if one match, or a list if multiple.
|
|
245
|
+
|
|
246
|
+
```python
|
|
247
|
+
model = org.devices.supported_devices.get("Cisco 8865")
|
|
248
|
+
# Returns a SupportedDevice dataclass
|
|
249
|
+
|
|
250
|
+
all_cisco_models = org.devices.supported_devices.get("Cisco")
|
|
251
|
+
# Returns a list of SupportedDevice
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
#### SupportedDevice Attributes
|
|
255
|
+
|
|
256
|
+
| Attribute | Type | Description |
|
|
257
|
+
|---|---|---|
|
|
258
|
+
| `model` | `str` | Model string (e.g. `"DMS Cisco 8865"`) |
|
|
259
|
+
| `display_name` | `str` | Human-friendly display name |
|
|
260
|
+
| `type` | `str` | Device type |
|
|
261
|
+
| `manufacturer` | `str` | Manufacturer name |
|
|
262
|
+
| `managed_by` | `str` | `"CISCO"` or third-party |
|
|
263
|
+
| `supported_for` | `list` | `["PEOPLE"]`, `["PLACE"]`, or both |
|
|
264
|
+
| `onboarding_method` | `list` | e.g. `["ACTIVATION_CODE", "MAC_ADDRESS"]` |
|
|
265
|
+
| `number_of_line_ports` | `int` | Number of line ports |
|
|
266
|
+
| `kem_support_enabled` | `bool` | KEM module support |
|
|
267
|
+
| `kem_module_count` | `int\|None` | Number of KEM modules supported |
|
|
268
|
+
| `kem_module_type` | `list\|None` | KEM module types |
|
|
269
|
+
| `allow_configure_layout_enabled` | `bool` | Layout configuration support |
|
|
270
|
+
| `allow_configure_ports_enabled` | `bool` | Port configuration support |
|
|
271
|
+
| `customizable_line_label_enabled` | `bool` | Custom line labels support |
|
|
272
|
+
| `upgrade_channel_enabled` | `bool` | Multiple upgrade channels |
|
|
273
|
+
| `customized_behaviors_enabled` | `bool` | Custom behaviors support |
|
|
274
|
+
| `default_upgrade_channel` | `str\|None` | Default upgrade channel |
|
|
275
|
+
| `additional_primary_line_appearances_enabled` | `bool\|None` | Additional PLA support |
|
|
276
|
+
| `basic_emergency_nomadic_enabled` | `bool\|None` | HELD support |
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## Device Members & Layout
|
|
281
|
+
|
|
282
|
+
### DeviceMemberList
|
|
283
|
+
|
|
284
|
+
Each device has a `members` property returning a `DeviceMemberList` -- the configured lines on the phone.
|
|
285
|
+
|
|
286
|
+
```python
|
|
287
|
+
members = device.members
|
|
288
|
+
print(members.max_line_count) # e.g. 10
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
#### `DeviceMemberList.add(...)`
|
|
292
|
+
|
|
293
|
+
Add a configured line (shared line appearance, primary line, etc.) to the device.
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
DeviceMemberList.add(
|
|
297
|
+
members: Person | Workspace | VirtualLine | list,
|
|
298
|
+
line_type: str = 'shared', # "primary" or "shared"
|
|
299
|
+
line_label: Optional[str] = None, # MPP only via this API; 9800-series uses Phone.LineKeyLabel PhoneOS config key instead
|
|
300
|
+
hotline_enabled: bool = False,
|
|
301
|
+
hotline_destination: Optional[str] = None,
|
|
302
|
+
allow_call_decline: bool = False
|
|
303
|
+
) -> bool
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
```python
|
|
307
|
+
# Add a shared line appearance
|
|
308
|
+
device.members.add(some_person, line_type='shared', line_label="Sales")
|
|
309
|
+
|
|
310
|
+
# Add multiple members at once (all get same settings)
|
|
311
|
+
device.members.add([person_a, person_b], line_type='shared')
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
**ATA note:** For Cisco 191/192 ATAs, the `t38FaxCompression` field is automatically set to `False` in the payload.
|
|
315
|
+
|
|
316
|
+
#### `DeviceMemberList.available_members()`
|
|
317
|
+
|
|
318
|
+
Returns a list of People and Workspaces eligible for assignment to this device.
|
|
319
|
+
|
|
320
|
+
#### `DeviceMemberList.ports_available()`
|
|
321
|
+
|
|
322
|
+
Returns a list of available port numbers.
|
|
323
|
+
|
|
324
|
+
#### `DeviceMemberList.port_map()`
|
|
325
|
+
|
|
326
|
+
Returns a dict mapping every port number to its assigned `DeviceMember` (or `None` if unassigned).
|
|
327
|
+
|
|
328
|
+
```python
|
|
329
|
+
port_map = device.members.port_map()
|
|
330
|
+
# {1: <DeviceMember>, 2: None, 3: None, ...}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
#### `DeviceMemberList.get(person=None, workspace=None)`
|
|
334
|
+
|
|
335
|
+
Find a specific member on the device.
|
|
336
|
+
|
|
337
|
+
#### `DeviceMemberList.refresh()`
|
|
338
|
+
|
|
339
|
+
Re-fetch configured lines from Webex.
|
|
340
|
+
|
|
341
|
+
### DeviceMember
|
|
342
|
+
|
|
343
|
+
Represents a single configured line on a device.
|
|
344
|
+
|
|
345
|
+
#### DeviceMember Attributes
|
|
346
|
+
|
|
347
|
+
| Attribute | Type | Description |
|
|
348
|
+
|---|---|---|
|
|
349
|
+
| `id` | `str` | Member ID (Person/Workspace/VirtualLine ID) |
|
|
350
|
+
| `member_type` | `str` | `"person"` or `"workspace"` |
|
|
351
|
+
| `port` | `int` | Port/line number on the device |
|
|
352
|
+
| `primary_owner` | `bool` | Whether this is the primary owner |
|
|
353
|
+
| `line_type` | `str` | `"PRIMARY"` or `"SHARED_CALL_APPEARANCE"` |
|
|
354
|
+
| `line_weight` | `int` | Number of ports this line consumes |
|
|
355
|
+
| `hotline_enabled` | `bool` | Hotline status |
|
|
356
|
+
| `hotline_destination` | `str\|None` | Hotline destination number |
|
|
357
|
+
| `call_decline_all` | `bool` | Decline-all-devices behavior |
|
|
358
|
+
| `line_label` | `str\|None` | Custom line label (MPP only via this API — 9800-series uses `Phone.LineKeyLabel` / `Phone.LineKeySecondaryLabel` PhoneOS config keys via `device-configurations` instead) |
|
|
359
|
+
| `first_name` | `str\|None` | Member first name |
|
|
360
|
+
| `last_name` | `str\|None` | Member last name |
|
|
361
|
+
| `phone_number` | `str\|None` | Member phone number |
|
|
362
|
+
| `extension` | `str\|None` | Member extension |
|
|
363
|
+
| `esn` | `str\|None` | Enterprise Significant Number |
|
|
364
|
+
| `location_id` | `str\|None` | Location ID |
|
|
365
|
+
|
|
366
|
+
#### `DeviceMember.set_line_label(label: str) -> DeviceMember`
|
|
367
|
+
|
|
368
|
+
Set or update the line label on the device. MPP devices only.
|
|
369
|
+
|
|
370
|
+
```python
|
|
371
|
+
member = device.members.get(person=some_person)
|
|
372
|
+
member.set_line_label("Front Desk")
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### `DeviceMember.set_hotline(enabled: bool, destination: Optional[str]) -> DeviceMember`
|
|
376
|
+
|
|
377
|
+
Enable or disable hotline for the line.
|
|
378
|
+
|
|
379
|
+
```python
|
|
380
|
+
member.set_hotline(enabled=True, destination="+15551234567")
|
|
381
|
+
member.set_hotline(enabled=False)
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
#### `DeviceMember.set_call_decline_all(enabled: bool) -> DeviceMember`
|
|
385
|
+
|
|
386
|
+
Control decline behavior. When `True`, declining on this device declines on all devices. When `False`, only silences this device.
|
|
387
|
+
|
|
388
|
+
### DeviceLayout
|
|
389
|
+
|
|
390
|
+
Manages the key layout on a device (line keys and KEM keys).
|
|
391
|
+
|
|
392
|
+
#### DeviceLayout Attributes
|
|
393
|
+
|
|
394
|
+
| Attribute | Type | Description |
|
|
395
|
+
|---|---|---|
|
|
396
|
+
| `layout_mode` | `str` | Layout mode |
|
|
397
|
+
| `user_reorder_enabled` | `bool` | Whether user can reorder |
|
|
398
|
+
| `line_keys` | `list` | Line key configuration |
|
|
399
|
+
| `kem_type` | `str\|None` | KEM module type |
|
|
400
|
+
| `kem_keys` | `list\|None` | KEM key configuration |
|
|
401
|
+
|
|
402
|
+
#### Reading and Setting Layout
|
|
403
|
+
|
|
404
|
+
```python
|
|
405
|
+
layout = device.layout
|
|
406
|
+
print(layout.line_keys)
|
|
407
|
+
|
|
408
|
+
# Modify and apply
|
|
409
|
+
layout.line_keys = [...] # See Webex Developer docs for format
|
|
410
|
+
device.set_layout(layout)
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
The `line_keys` and `kem_keys` lists use the raw format from the Webex Developer documentation. See: https://developer.webex.com/docs/api/v1/device-call-settings/modify-device-layout-by-device-id
|
|
414
|
+
|
|
415
|
+
---
|
|
416
|
+
|
|
417
|
+
## DECT Networks
|
|
418
|
+
|
|
419
|
+
Source: `wxcadm/dect.py`
|
|
420
|
+
|
|
421
|
+
DECT networks manage Cisco DBS110/DBS210 base stations and their associated handsets.
|
|
422
|
+
|
|
423
|
+
### Access Pattern
|
|
424
|
+
|
|
425
|
+
```python
|
|
426
|
+
# Org-level — all DECT networks
|
|
427
|
+
dect_networks = DECTNetworkList(org)
|
|
428
|
+
|
|
429
|
+
# Location-level — DECT networks at a specific location
|
|
430
|
+
dect_networks = DECTNetworkList(org, location=location)
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
**Note:** Both `org.dect_networks` and `location.dect_networks` property accessors exist and return `DECTNetworkList` instances. Direct instantiation (`DECTNetworkList(org)` or `DECTNetworkList(org, location=location)`) also works.
|
|
434
|
+
|
|
435
|
+
### DECTNetworkList Methods
|
|
436
|
+
|
|
437
|
+
#### `DECTNetworkList.create(...)`
|
|
438
|
+
|
|
439
|
+
Create a new DECT network.
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
DECTNetworkList.create(
|
|
443
|
+
name: str,
|
|
444
|
+
model: str, # "DBS110", "110", "DBS210", or "210"
|
|
445
|
+
default_access_code: Optional[str] = None,
|
|
446
|
+
handset_display_name: Optional[str] = None,
|
|
447
|
+
location: Optional[Location] = None # Required for Org-level lists
|
|
448
|
+
) -> DECTNetwork
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
The `model` parameter is normalized internally:
|
|
452
|
+
- `"110"` or `"DBS110"` becomes `"DMS Cisco DBS110"`
|
|
453
|
+
- `"210"` or `"DBS210"` becomes `"DMS Cisco DBS210"`
|
|
454
|
+
|
|
455
|
+
```python
|
|
456
|
+
network = dect_networks.create(
|
|
457
|
+
name="Building A DECT",
|
|
458
|
+
model="DBS210",
|
|
459
|
+
default_access_code="1234",
|
|
460
|
+
location=building_a_location
|
|
461
|
+
)
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
#### `DECTNetworkList.delete(network: DECTNetwork)`
|
|
465
|
+
|
|
466
|
+
Delete a DECT network. Returns the updated `DECTNetworkList`.
|
|
467
|
+
|
|
468
|
+
#### `DECTNetworkList.refresh()`
|
|
469
|
+
|
|
470
|
+
Re-query the list from Webex.
|
|
471
|
+
|
|
472
|
+
#### `DECTNetworkList.with_base_stations(count=1)`
|
|
473
|
+
|
|
474
|
+
Filter to networks with at least `count` base stations.
|
|
475
|
+
|
|
476
|
+
#### `DECTNetworkList.with_handsets(count=1)`
|
|
477
|
+
|
|
478
|
+
Filter to networks with at least `count` handsets assigned.
|
|
479
|
+
|
|
480
|
+
### DECTNetwork Attributes
|
|
481
|
+
|
|
482
|
+
| Attribute | Type | Description |
|
|
483
|
+
|---|---|---|
|
|
484
|
+
| `id` | `str` | Network ID |
|
|
485
|
+
| `name` | `str` | Network name |
|
|
486
|
+
| `display_name` | `str` | Display name |
|
|
487
|
+
| `chain_id` | `str` | Chain ID |
|
|
488
|
+
| `model` | `str` | Base station model |
|
|
489
|
+
| `default_access_code_enabled` | `bool` | Whether default access code is on |
|
|
490
|
+
| `default_access_code` | `str` | The default access code |
|
|
491
|
+
| `number_of_base_stations` | `int` | Count of base stations |
|
|
492
|
+
| `number_of_handsets_assigned` | `int` | Count of assigned handsets |
|
|
493
|
+
| `number_of_lines` | `int` | Count of lines |
|
|
494
|
+
| `location_id` | `str` | Location ID |
|
|
495
|
+
|
|
496
|
+
### DECTNetwork Methods
|
|
497
|
+
|
|
498
|
+
#### `DECTNetwork.base_stations` (property)
|
|
499
|
+
|
|
500
|
+
Returns a list of `DECTBaseStation` instances.
|
|
501
|
+
|
|
502
|
+
#### `DECTNetwork.handsets` (property)
|
|
503
|
+
|
|
504
|
+
Returns a list of `DECTHandset` instances.
|
|
505
|
+
|
|
506
|
+
#### `DECTNetwork.add_base_stations(mac_list: list) -> list[DECTBaseStation]`
|
|
507
|
+
|
|
508
|
+
Add one or more base stations by MAC address. Returns the full list of base stations (including pre-existing ones).
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
stations = network.add_base_stations(["AABBCCDDEEFF", "112233445566"])
|
|
512
|
+
```
|
|
513
|
+
|
|
514
|
+
#### `DECTNetwork.delete_base_station(base_station: str | DECTBaseStation) -> list`
|
|
515
|
+
|
|
516
|
+
Delete a base station by `DECTBaseStation` instance or MAC address string. Returns remaining base stations.
|
|
517
|
+
|
|
518
|
+
```python
|
|
519
|
+
network.delete_base_station("AABBCCDDEEFF")
|
|
520
|
+
```
|
|
521
|
+
|
|
522
|
+
#### `DECTNetwork.get_base_station(mac: str) -> Optional[DECTBaseStation]`
|
|
523
|
+
|
|
524
|
+
Find a base station by MAC address.
|
|
525
|
+
|
|
526
|
+
#### `DECTNetwork.add_handset(...)`
|
|
527
|
+
|
|
528
|
+
Add a handset to the network.
|
|
529
|
+
|
|
530
|
+
```python
|
|
531
|
+
DECTNetwork.add_handset(
|
|
532
|
+
display_name: str, # 16 chars max
|
|
533
|
+
line1: Person | Workspace, # Required
|
|
534
|
+
line2: Optional[Person | Workspace] # Optional second line
|
|
535
|
+
) -> bool
|
|
536
|
+
```
|
|
537
|
+
|
|
538
|
+
```python
|
|
539
|
+
network.add_handset(
|
|
540
|
+
display_name="Warehouse 1",
|
|
541
|
+
line1=warehouse_workspace,
|
|
542
|
+
line2=manager_person
|
|
543
|
+
)
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
#### `DECTNetwork.delete_handset(handset: DECTHandset) -> list`
|
|
547
|
+
|
|
548
|
+
Delete a handset. Returns remaining handsets.
|
|
549
|
+
|
|
550
|
+
#### `DECTNetwork.set_name(name: str, display_name: Optional[str]) -> bool`
|
|
551
|
+
|
|
552
|
+
Change the network name (and optionally display name).
|
|
553
|
+
|
|
554
|
+
#### `DECTNetwork.set_display_name(display_name: str) -> bool`
|
|
555
|
+
|
|
556
|
+
Change only the display name.
|
|
557
|
+
|
|
558
|
+
#### `DECTNetwork.enable_default_access_code(access_code: Optional[str]) -> bool`
|
|
559
|
+
|
|
560
|
+
Enable the default access code. If the code was previously set and disabled, it can be re-enabled without passing the code again.
|
|
561
|
+
|
|
562
|
+
Raises `ValueError` if no code exists and none is provided.
|
|
563
|
+
|
|
564
|
+
#### `DECTNetwork.disable_default_access_code() -> bool`
|
|
565
|
+
|
|
566
|
+
Disable the default access code (preserves the stored code value).
|
|
567
|
+
|
|
568
|
+
#### `DECTNetwork.delete() -> bool`
|
|
569
|
+
|
|
570
|
+
Delete the entire DECT network.
|
|
571
|
+
|
|
572
|
+
### DECTBaseStation
|
|
573
|
+
|
|
574
|
+
| Attribute | Type | Description |
|
|
575
|
+
|---|---|---|
|
|
576
|
+
| `id` | `str` | Base station ID |
|
|
577
|
+
| `mac` | `str` | MAC address (uppercase) |
|
|
578
|
+
| `number_of_lines_registered` | `int` | Lines registered to this base |
|
|
579
|
+
|
|
580
|
+
#### `DECTBaseStation.delete() -> bool`
|
|
581
|
+
|
|
582
|
+
Delete the base station.
|
|
583
|
+
|
|
584
|
+
#### `DECTBaseStation.get_handsets() -> list[DECTHandset]`
|
|
585
|
+
|
|
586
|
+
Get handsets associated with this specific base station.
|
|
587
|
+
|
|
588
|
+
### DECTHandset
|
|
589
|
+
|
|
590
|
+
| Attribute | Type | Description |
|
|
591
|
+
|---|---|---|
|
|
592
|
+
| `id` | `str` | Handset ID |
|
|
593
|
+
| `index` | `str` | Handset index |
|
|
594
|
+
| `display_name` | `str` | Display name |
|
|
595
|
+
| `access_code` | `str` | Access code |
|
|
596
|
+
| `lines` | `list` | Configured lines |
|
|
597
|
+
| `mac` | `str` (property) | MAC address (lazy-loaded) |
|
|
598
|
+
|
|
599
|
+
#### `DECTHandset.delete() -> bool`
|
|
600
|
+
|
|
601
|
+
Delete the handset.
|
|
602
|
+
|
|
603
|
+
#### `DECTHandset.set_handset_display_name(display_name: str) -> bool`
|
|
604
|
+
|
|
605
|
+
Change the text displayed on the handset screen.
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## Workspace Class
|
|
610
|
+
|
|
611
|
+
Source: `wxcadm/workspace.py`
|
|
612
|
+
|
|
613
|
+
Workspaces represent shared physical locations (conference rooms, lobby phones, common areas) in Webex Calling.
|
|
614
|
+
|
|
615
|
+
### Access Pattern
|
|
616
|
+
|
|
617
|
+
```python
|
|
618
|
+
# Org-level
|
|
619
|
+
workspaces = org.workspaces # WorkspaceList
|
|
620
|
+
|
|
621
|
+
# Location-level
|
|
622
|
+
workspaces = WorkspaceList(org, location=location)
|
|
623
|
+
```
|
|
624
|
+
|
|
625
|
+
### WorkspaceList Methods
|
|
626
|
+
|
|
627
|
+
#### `WorkspaceList.create(...)`
|
|
628
|
+
|
|
629
|
+
Create a new Workspace with Webex Calling enabled.
|
|
630
|
+
|
|
631
|
+
```python
|
|
632
|
+
WorkspaceList.create(
|
|
633
|
+
location: Location,
|
|
634
|
+
name: str,
|
|
635
|
+
floor: Optional[LocationFloor] = None,
|
|
636
|
+
capacity: Optional[int] = None,
|
|
637
|
+
type: Optional[str] = 'notSet', # See types below
|
|
638
|
+
phone_number: Optional[str] = None,
|
|
639
|
+
extension: Optional[str] = None,
|
|
640
|
+
notes: Optional[str] = None,
|
|
641
|
+
hotdesking: Optional[bool] = False,
|
|
642
|
+
supported_devices: Optional[str] = 'phones', # "phones" or "collaborationDevices"
|
|
643
|
+
license_type: str = 'workspace', # "workspace", "professional", or "hotdesk"
|
|
644
|
+
ignore_license_overage: Optional[bool] = True
|
|
645
|
+
) -> Workspace
|
|
646
|
+
```
|
|
647
|
+
|
|
648
|
+
**Workspace types:** `"notSet"`, `"focus"`, `"huddle"`, `"meetingRoom"`, `"open"`, `"desk"`, `"other"`
|
|
649
|
+
|
|
650
|
+
**License types:**
|
|
651
|
+
- `"workspace"` -- Standard Workspace license
|
|
652
|
+
- `"professional"` -- Professional license (full calling features)
|
|
653
|
+
- `"hotdesk"` -- Hot Desking license (requires `hotdesking=True`)
|
|
654
|
+
|
|
655
|
+
```python
|
|
656
|
+
lobby = workspaces.create(
|
|
657
|
+
location=hq_location,
|
|
658
|
+
name="Main Lobby",
|
|
659
|
+
extension="8100",
|
|
660
|
+
phone_number="+15559998100",
|
|
661
|
+
type="open",
|
|
662
|
+
supported_devices="phones",
|
|
663
|
+
license_type="workspace"
|
|
664
|
+
)
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Raises:
|
|
668
|
+
- `ValueError` if neither `extension` nor `phone_number` is provided (unless `hotdesk` license)
|
|
669
|
+
- `wxcadm.NotSubscribedForLicenseError` if the license type is not available
|
|
670
|
+
- `wxcadm.LicenseOverageError` if `ignore_license_overage=False` and assignment would exceed count
|
|
671
|
+
|
|
672
|
+
#### `WorkspaceList.get(id=None, name=None, uuid=None)`
|
|
673
|
+
|
|
674
|
+
Find a workspace by ID, name, or UUID.
|
|
675
|
+
|
|
676
|
+
```python
|
|
677
|
+
ws = workspaces.get(name="Main Lobby")
|
|
678
|
+
ws = workspaces.get(id="some-workspace-id")
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### `WorkspaceList.get_by_id(id: str)`
|
|
682
|
+
|
|
683
|
+
Find a workspace by ID only.
|
|
684
|
+
|
|
685
|
+
#### `WorkspaceList.webex_calling()`
|
|
686
|
+
|
|
687
|
+
Return only workspaces with Webex Calling enabled.
|
|
688
|
+
|
|
689
|
+
#### `WorkspaceList.professional()`
|
|
690
|
+
|
|
691
|
+
Return only workspaces with a Professional license.
|
|
692
|
+
|
|
693
|
+
#### `WorkspaceList.refresh()`
|
|
694
|
+
|
|
695
|
+
Re-query the workspace list from Webex.
|
|
696
|
+
|
|
697
|
+
### Workspace Attributes
|
|
698
|
+
|
|
699
|
+
| Attribute | Type | Description |
|
|
700
|
+
|---|---|---|
|
|
701
|
+
| `id` | `str` | Workspace ID |
|
|
702
|
+
| `name` | `str` | Display name |
|
|
703
|
+
| `org` | `Org` | Parent org |
|
|
704
|
+
| `location` | `Location\|None` | Assigned location |
|
|
705
|
+
| `capacity` | `int` | Room capacity |
|
|
706
|
+
| `type` | `str` | Workspace type |
|
|
707
|
+
| `sip_address` | `str` | SIP URI |
|
|
708
|
+
| `calling` | `str` | Calling type (`webexCalling`, `freeCalling`, etc.) |
|
|
709
|
+
| `calendar` | `dict\|None` | Calendar connector info |
|
|
710
|
+
| `notes` | `str` | Free-form notes |
|
|
711
|
+
| `licenses` | `list` | Assigned license IDs |
|
|
712
|
+
| `created` | `str` | Creation timestamp |
|
|
713
|
+
|
|
714
|
+
### Workspace Properties
|
|
715
|
+
|
|
716
|
+
#### `Workspace.number` (property)
|
|
717
|
+
|
|
718
|
+
Returns the phone number. Single number returns a string; multiple numbers returns a list. Makes an API call on first access.
|
|
719
|
+
|
|
720
|
+
#### `Workspace.extension` (property)
|
|
721
|
+
|
|
722
|
+
Returns the extension. Same single/list behavior as `number`.
|
|
723
|
+
|
|
724
|
+
#### `Workspace.esn` (property)
|
|
725
|
+
|
|
726
|
+
The Enterprise Significant Number.
|
|
727
|
+
|
|
728
|
+
#### `Workspace.devices` (property)
|
|
729
|
+
|
|
730
|
+
Returns the `DeviceList` for this workspace.
|
|
731
|
+
|
|
732
|
+
#### `Workspace.caller_id` (property)
|
|
733
|
+
|
|
734
|
+
Returns the Caller ID settings as a dict.
|
|
735
|
+
|
|
736
|
+
#### `Workspace.ecbn` (property)
|
|
737
|
+
|
|
738
|
+
Returns the Emergency Callback Number details.
|
|
739
|
+
|
|
740
|
+
#### `Workspace.barge_in` (property)
|
|
741
|
+
|
|
742
|
+
Returns the `BargeInSettings` for the workspace, or `None` if not configured.
|
|
743
|
+
|
|
744
|
+
#### `Workspace.monitoring` (property)
|
|
745
|
+
|
|
746
|
+
Returns the `MonitoringList` associated with the workspace.
|
|
747
|
+
|
|
748
|
+
#### `Workspace.license_type` (property)
|
|
749
|
+
|
|
750
|
+
Returns the license type: `"WORKSPACE"`, `"PROFESSIONAL"`, `"HOTDESK"`, `"MULTIPLE"`, or `None`.
|
|
751
|
+
|
|
752
|
+
#### `Workspace.spark_id` (property)
|
|
753
|
+
|
|
754
|
+
The internal Webex identifier (decoded from base64).
|
|
755
|
+
|
|
756
|
+
### Workspace Methods
|
|
757
|
+
|
|
758
|
+
#### `Workspace.set_caller_id(name, number, block_for_received_calls=False) -> bool`
|
|
759
|
+
|
|
760
|
+
Set the Caller ID for the workspace.
|
|
761
|
+
|
|
762
|
+
```python
|
|
763
|
+
Workspace.set_caller_id(
|
|
764
|
+
name: str, # "direct", "location", or custom string
|
|
765
|
+
number: str, # "direct", "location", or custom number
|
|
766
|
+
block_for_received_calls: Optional[bool] = False
|
|
767
|
+
) -> bool
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
```python
|
|
771
|
+
workspace.set_caller_id(name="Main Lobby", number="direct")
|
|
772
|
+
workspace.set_caller_id(name="location", number="location")
|
|
773
|
+
workspace.set_caller_id(name="Custom Name", number="+15551234567")
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
#### `Workspace.set_ecbn(value) -> bool`
|
|
777
|
+
|
|
778
|
+
Set the Emergency Callback Number.
|
|
779
|
+
|
|
780
|
+
```python
|
|
781
|
+
# Use the workspace's own direct line
|
|
782
|
+
workspace.set_ecbn("direct")
|
|
783
|
+
|
|
784
|
+
# Use the location ECBN
|
|
785
|
+
workspace.set_ecbn("location")
|
|
786
|
+
|
|
787
|
+
# Use another member's number
|
|
788
|
+
workspace.set_ecbn(some_person) # Person, Workspace, or VirtualLine
|
|
789
|
+
```
|
|
790
|
+
|
|
791
|
+
#### `Workspace.assign_wxc(...) -> bool`
|
|
792
|
+
|
|
793
|
+
Enable Webex Calling for a workspace that does not currently have it.
|
|
794
|
+
|
|
795
|
+
```python
|
|
796
|
+
Workspace.assign_wxc(
|
|
797
|
+
location: Location,
|
|
798
|
+
phone_number: Optional[str] = None,
|
|
799
|
+
extension: Optional[str] = None,
|
|
800
|
+
license_type: str = 'workspace',
|
|
801
|
+
ignore_license_overage: bool = True
|
|
802
|
+
) -> bool
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
#### `Workspace.unassign_wxc() -> bool`
|
|
806
|
+
|
|
807
|
+
Disable Webex Calling. Only works for workspaces with `supportedDevices="collaborationDevices"`. Phone-based workspaces must be deleted and recreated.
|
|
808
|
+
|
|
809
|
+
#### `Workspace.set_professional_license() -> bool`
|
|
810
|
+
|
|
811
|
+
Upgrade the workspace to a Professional license. No-op if already Professional.
|
|
812
|
+
|
|
813
|
+
#### `Workspace.set_hotdesk(enabled=True) -> bool`
|
|
814
|
+
|
|
815
|
+
Enable or disable hot desking.
|
|
816
|
+
|
|
817
|
+
#### `Workspace.delete() -> bool`
|
|
818
|
+
|
|
819
|
+
Delete the workspace entirely.
|
|
820
|
+
|
|
821
|
+
#### `Workspace.get_config()`
|
|
822
|
+
|
|
823
|
+
Refresh the workspace config from the API.
|
|
824
|
+
|
|
825
|
+
#### `Workspace.get_monitored_by()`
|
|
826
|
+
|
|
827
|
+
Returns a list of users/workspaces that are monitoring this workspace.
|
|
828
|
+
|
|
829
|
+
---
|
|
830
|
+
|
|
831
|
+
## Virtual Lines
|
|
832
|
+
|
|
833
|
+
Source: `wxcadm/virtual_line.py`
|
|
834
|
+
|
|
835
|
+
Virtual Lines represent phone identities that are not tied to a specific person -- used for shared numbers, lobby lines, or lines that appear on multiple devices.
|
|
836
|
+
|
|
837
|
+
### Access Pattern
|
|
838
|
+
|
|
839
|
+
```python
|
|
840
|
+
# Org-level
|
|
841
|
+
virtual_lines = org.virtual_lines # VirtualLineList
|
|
842
|
+
|
|
843
|
+
# Location-level
|
|
844
|
+
virtual_lines = VirtualLineList(org, location=location)
|
|
845
|
+
```
|
|
846
|
+
|
|
847
|
+
### VirtualLineList Methods
|
|
848
|
+
|
|
849
|
+
#### `VirtualLineList.create(...)`
|
|
850
|
+
|
|
851
|
+
Create a new Virtual Line.
|
|
852
|
+
|
|
853
|
+
```python
|
|
854
|
+
VirtualLineList.create(
|
|
855
|
+
first_name: str,
|
|
856
|
+
last_name: str,
|
|
857
|
+
phone_number: Optional[str] = None,
|
|
858
|
+
extension: Optional[str] = None,
|
|
859
|
+
location: Optional[Location | str] = None, # Required for Org-level lists
|
|
860
|
+
caller_id_first_name: Optional[str] = None,
|
|
861
|
+
caller_id_last_name: Optional[str] = None,
|
|
862
|
+
caller_id_number: Optional[str] = None
|
|
863
|
+
) -> VirtualLine
|
|
864
|
+
```
|
|
865
|
+
|
|
866
|
+
At least one of `phone_number` or `extension` is required.
|
|
867
|
+
|
|
868
|
+
```python
|
|
869
|
+
vl = virtual_lines.create(
|
|
870
|
+
first_name="Sales",
|
|
871
|
+
last_name="Line",
|
|
872
|
+
extension="8200",
|
|
873
|
+
phone_number="+15559998200",
|
|
874
|
+
location=hq_location
|
|
875
|
+
)
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
**Note:** The returned `VirtualLine` only has the `id` populated initially. Call `vl.refresh_config()` to populate all fields.
|
|
879
|
+
|
|
880
|
+
#### `VirtualLineList.get(...)`
|
|
881
|
+
|
|
882
|
+
Find a virtual line by ID or name.
|
|
883
|
+
|
|
884
|
+
```python
|
|
885
|
+
VirtualLineList.get(
|
|
886
|
+
id: Optional[str] = None,
|
|
887
|
+
first_name: Optional[str] = None,
|
|
888
|
+
last_name: Optional[str] = None,
|
|
889
|
+
name: Optional[str] = None # "first last" shortcut
|
|
890
|
+
) -> Optional[VirtualLine]
|
|
891
|
+
```
|
|
892
|
+
|
|
893
|
+
```python
|
|
894
|
+
vl = virtual_lines.get(name="Sales Line")
|
|
895
|
+
vl = virtual_lines.get(first_name="Sales", last_name="Line")
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
Name matching is case-insensitive. Both `first_name` and `last_name` are required when searching by name (unless using the `name` shortcut).
|
|
899
|
+
|
|
900
|
+
#### `VirtualLineList.refresh()`
|
|
901
|
+
|
|
902
|
+
Re-query from Webex.
|
|
903
|
+
|
|
904
|
+
### VirtualLine Attributes
|
|
905
|
+
|
|
906
|
+
| Attribute | Type | Description |
|
|
907
|
+
|---|---|---|
|
|
908
|
+
| `id` | `str` | Virtual Line ID |
|
|
909
|
+
| `first_name` | `str` | First name |
|
|
910
|
+
| `last_name` | `str` | Last name |
|
|
911
|
+
| `caller_id_first_name` | `str` | Caller ID first name |
|
|
912
|
+
| `caller_id_last_name` | `str` | Caller ID last name |
|
|
913
|
+
| `caller_id_number` | `str` | Caller ID number |
|
|
914
|
+
| `external_caller_id_policy` | `str` | External caller ID policy |
|
|
915
|
+
| `extension` | `str\|None` | Extension |
|
|
916
|
+
| `esn` | `str\|None` | Enterprise Significant Number |
|
|
917
|
+
| `phone_number` | `str\|None` | DID phone number |
|
|
918
|
+
| `location_id` | `str` | Location ID |
|
|
919
|
+
| `billing_plan` | `str` | Billing plan |
|
|
920
|
+
| `num_devices_assigned` | `int` | Count of assigned devices |
|
|
921
|
+
|
|
922
|
+
### VirtualLine Properties (Lazy-Loaded)
|
|
923
|
+
|
|
924
|
+
These trigger a detail API call on first access:
|
|
925
|
+
|
|
926
|
+
| Property | Type | Description |
|
|
927
|
+
|---|---|---|
|
|
928
|
+
| `display_name` | `str` | Full display name |
|
|
929
|
+
| `name` | `str` | Alias for `display_name` |
|
|
930
|
+
| `directory_search_enabled` | `bool` | Directory search visibility |
|
|
931
|
+
| `announcement_language` | `str` | Announcement language |
|
|
932
|
+
| `time_zone` | `str` | Time zone |
|
|
933
|
+
| `ecbn` | `dict` | Emergency Callback Number details |
|
|
934
|
+
|
|
935
|
+
### VirtualLine Methods
|
|
936
|
+
|
|
937
|
+
#### `VirtualLine.update(**kwargs) -> bool`
|
|
938
|
+
|
|
939
|
+
Update any attribute(s) with keyword arguments.
|
|
940
|
+
|
|
941
|
+
```python
|
|
942
|
+
vl.update(first_name="Reception", last_name="Desk")
|
|
943
|
+
vl.update(phone_number="+15559998201")
|
|
944
|
+
vl.update(extension="8201", time_zone="America/New_York")
|
|
945
|
+
```
|
|
946
|
+
|
|
947
|
+
Raises `AttributeError` if you pass a non-existing attribute.
|
|
948
|
+
|
|
949
|
+
#### `VirtualLine.set_ecbn(value)`
|
|
950
|
+
|
|
951
|
+
Set the Emergency Callback Number. Same interface as `Workspace.set_ecbn()`.
|
|
952
|
+
|
|
953
|
+
```python
|
|
954
|
+
vl.set_ecbn("direct")
|
|
955
|
+
vl.set_ecbn("location")
|
|
956
|
+
vl.set_ecbn(some_person)
|
|
957
|
+
```
|
|
958
|
+
|
|
959
|
+
#### `VirtualLine.enable_call_recording(...) -> bool`
|
|
960
|
+
|
|
961
|
+
Enable and configure call recording.
|
|
962
|
+
|
|
963
|
+
```python
|
|
964
|
+
VirtualLine.enable_call_recording(
|
|
965
|
+
type: str, # "always", "never", "always_with_pause", "on_demand"
|
|
966
|
+
record_vm: bool = False,
|
|
967
|
+
announcement_enabled: bool = False,
|
|
968
|
+
reminder_tone: bool = False,
|
|
969
|
+
reminder_interval: int = 30,
|
|
970
|
+
can_play: bool = True,
|
|
971
|
+
can_download: bool = True,
|
|
972
|
+
can_delete: bool = True,
|
|
973
|
+
can_share: bool = True,
|
|
974
|
+
transcribe: bool = True,
|
|
975
|
+
ai_summary: bool = True
|
|
976
|
+
) -> bool
|
|
977
|
+
```
|
|
978
|
+
|
|
979
|
+
```python
|
|
980
|
+
vl.enable_call_recording(
|
|
981
|
+
type="always",
|
|
982
|
+
announcement_enabled=True,
|
|
983
|
+
transcribe=True,
|
|
984
|
+
ai_summary=True
|
|
985
|
+
)
|
|
986
|
+
```
|
|
987
|
+
|
|
988
|
+
**Note:** The `transcribe`, `can_play`, etc. parameters only apply to Webex-platform recording. Third-party recording providers ignore them.
|
|
989
|
+
|
|
990
|
+
#### `VirtualLine.disable_call_recording() -> bool`
|
|
991
|
+
|
|
992
|
+
Disable call recording. Returns `True` even if recording was not previously enabled.
|
|
993
|
+
|
|
994
|
+
#### `VirtualLine.get_call_recording() -> dict`
|
|
995
|
+
|
|
996
|
+
Returns the current call recording configuration.
|
|
997
|
+
|
|
998
|
+
**Bug:** This method has a confirmed bug in the source -- it passes `'get'` as the first positional argument to `self.org.api.get()`, where the first parameter is `endpoint`. The actual URL `v1/telephony/config/virtualLines/{id}/callRecording` is passed as the second argument, which maps to `params`. This will cause an incorrect API call. Use raw HTTP as a workaround: `GET /v1/telephony/config/virtualLines/{id}/callRecording`.
|
|
999
|
+
|
|
1000
|
+
#### `VirtualLine.refresh_config() -> bool`
|
|
1001
|
+
|
|
1002
|
+
Re-fetch the Virtual Line config from Webex. Useful after `create()` since the initial instance only has the ID.
|
|
1003
|
+
|
|
1004
|
+
#### `VirtualLine.delete() -> bool`
|
|
1005
|
+
|
|
1006
|
+
Delete the Virtual Line.
|
|
1007
|
+
|
|
1008
|
+
**Bug:** The `delete()` method returns `False` on success. This is a confirmed bug in the source -- the method explicitly `return False` after the API call succeeds, while other `delete()` methods in wxcadm return `True`.
|
|
1009
|
+
|
|
1010
|
+
#### `VirtualLine.get_monitored_by()`
|
|
1011
|
+
|
|
1012
|
+
Returns a list of users/workspaces monitoring this virtual line.
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
## Number Management
|
|
1017
|
+
|
|
1018
|
+
Source: `wxcadm/number.py`
|
|
1019
|
+
|
|
1020
|
+
### Access Pattern
|
|
1021
|
+
|
|
1022
|
+
```python
|
|
1023
|
+
# Org-level
|
|
1024
|
+
numbers = org.numbers # NumberList
|
|
1025
|
+
|
|
1026
|
+
# Location-level
|
|
1027
|
+
numbers = NumberList(org, location=location)
|
|
1028
|
+
```
|
|
1029
|
+
|
|
1030
|
+
### Number Dataclass
|
|
1031
|
+
|
|
1032
|
+
`Number` is a `@dataclass_json` decorated dataclass with automatic camelCase mapping.
|
|
1033
|
+
|
|
1034
|
+
| Attribute | Type | Description |
|
|
1035
|
+
|---|---|---|
|
|
1036
|
+
| `phone_number` | `str\|None` | The phone number (E.164) |
|
|
1037
|
+
| `extension` | `str\|None` | Extension |
|
|
1038
|
+
| `routing_prefix` | `str\|None` | Location routing prefix |
|
|
1039
|
+
| `esn` | `str\|None` | Enterprise Significant Number |
|
|
1040
|
+
| `state` | `str\|None` | Number state (`"ACTIVE"`, `"INACTIVE"`) |
|
|
1041
|
+
| `phone_number_type` | `str\|None` | Number type |
|
|
1042
|
+
| `included_telephony_types` | `str\|None` | Telephony types included |
|
|
1043
|
+
| `main_number` | `bool\|None` | Whether this is a location main number |
|
|
1044
|
+
| `toll_free_number` | `bool\|None` | Whether toll-free |
|
|
1045
|
+
| `location` | `Location\|dict` (property) | Resolved Location or raw dict |
|
|
1046
|
+
| `owner` | `Person\|Workspace\|VirtualLine\|...` (property) | Resolved owner |
|
|
1047
|
+
|
|
1048
|
+
The `owner` property resolves across multiple types: `PEOPLE`, `PLACE` (Workspace), `VIRTUAL_LINE`, `CALL_QUEUE`, `HUNT_GROUP`, `AUTO_ATTENDANT`, `PAGING_GROUP`, `VOICEMAIL_GROUP`, and `VOICE_MESSAGING` (voice portal).
|
|
1049
|
+
|
|
1050
|
+
#### `Number.activate() -> bool`
|
|
1051
|
+
|
|
1052
|
+
Activate the phone number at its location.
|
|
1053
|
+
|
|
1054
|
+
```python
|
|
1055
|
+
number = numbers.get(phone_number="+15551234567")
|
|
1056
|
+
number.activate()
|
|
1057
|
+
```
|
|
1058
|
+
|
|
1059
|
+
### NumberList Methods
|
|
1060
|
+
|
|
1061
|
+
#### `NumberList.get(...)`
|
|
1062
|
+
|
|
1063
|
+
Find numbers by various criteria.
|
|
1064
|
+
|
|
1065
|
+
```python
|
|
1066
|
+
NumberList.get(
|
|
1067
|
+
phone_number: Optional[str] = None, # Partial match supported
|
|
1068
|
+
extension: Optional[str] = None,
|
|
1069
|
+
esn: Optional[str] = None,
|
|
1070
|
+
state: Optional[str] = None,
|
|
1071
|
+
location: Optional[Location] = None
|
|
1072
|
+
) -> Optional[Number | list[Number]]
|
|
1073
|
+
```
|
|
1074
|
+
|
|
1075
|
+
Return type depends on the search:
|
|
1076
|
+
- `phone_number` or `esn`: Returns a single `Number` or `None`
|
|
1077
|
+
- `extension` + `location`: Returns a single `Number` or `None`
|
|
1078
|
+
- `extension` alone: Returns a `Number` if one match, `list` if multiple
|
|
1079
|
+
- `state` or `location` alone: Returns a `list`
|
|
1080
|
+
|
|
1081
|
+
```python
|
|
1082
|
+
num = numbers.get(phone_number="+15551234567")
|
|
1083
|
+
nums = numbers.get(state="ACTIVE")
|
|
1084
|
+
nums = numbers.get(location=hq_location)
|
|
1085
|
+
```
|
|
1086
|
+
|
|
1087
|
+
#### `NumberList.get_by_owner(owner)`
|
|
1088
|
+
|
|
1089
|
+
Find a number by its owner (Person, Workspace, VirtualLine, etc.).
|
|
1090
|
+
|
|
1091
|
+
```python
|
|
1092
|
+
num = numbers.get_by_owner(some_person)
|
|
1093
|
+
```
|
|
1094
|
+
|
|
1095
|
+
#### `NumberList.add(...)`
|
|
1096
|
+
|
|
1097
|
+
Add numbers to a location. Only supported for Local Gateway or Non-integrated PSTN locations.
|
|
1098
|
+
|
|
1099
|
+
```python
|
|
1100
|
+
NumberList.add(
|
|
1101
|
+
location: Location,
|
|
1102
|
+
numbers: list, # List of number strings
|
|
1103
|
+
number_type: Optional[str] = 'DID', # "DID" or "TOLLFREE"
|
|
1104
|
+
state: Optional[str] = 'ACTIVE' # "ACTIVE" or "INACTIVE"
|
|
1105
|
+
) -> NumberList
|
|
1106
|
+
```
|
|
1107
|
+
|
|
1108
|
+
```python
|
|
1109
|
+
numbers.add(
|
|
1110
|
+
location=hq_location,
|
|
1111
|
+
numbers=["+15551110001", "+15551110002", "+15551110003"],
|
|
1112
|
+
number_type="DID",
|
|
1113
|
+
state="ACTIVE"
|
|
1114
|
+
)
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
Returns the refreshed `NumberList`.
|
|
1118
|
+
|
|
1119
|
+
#### `NumberList.validate(numbers: list) -> dict`
|
|
1120
|
+
|
|
1121
|
+
Validate phone numbers before adding. Returns the Webex validation response.
|
|
1122
|
+
|
|
1123
|
+
```python
|
|
1124
|
+
result = numbers.validate(["+15551110001", "+15551110002"])
|
|
1125
|
+
```
|
|
1126
|
+
|
|
1127
|
+
#### `NumberList.refresh()`
|
|
1128
|
+
|
|
1129
|
+
Re-fetch the number list from Webex.
|
|
1130
|
+
|
|
1131
|
+
---
|
|
1132
|
+
|
|
1133
|
+
## wxcadm vs wxc_sdk
|
|
1134
|
+
|
|
1135
|
+
Both libraries wrap the same Webex Calling APIs, but they differ in design philosophy and usage patterns.
|
|
1136
|
+
|
|
1137
|
+
### Design Philosophy
|
|
1138
|
+
|
|
1139
|
+
| Aspect | wxcadm | wxc_sdk |
|
|
1140
|
+
|---|---|---|
|
|
1141
|
+
| Pattern | Object-oriented, stateful | Flat API wrapper, mostly stateless |
|
|
1142
|
+
| Data model | Rich classes with methods (e.g. `Device.apply_changes()`) | Pydantic models as data containers + separate API methods |
|
|
1143
|
+
| Lists | `UserList` subclasses with built-in filtering | API methods return plain lists of models |
|
|
1144
|
+
| Lazy loading | Properties fetch on first access (e.g. `Device.calling_id`, `VirtualLine.display_name`) | Explicit API calls required |
|
|
1145
|
+
| Authentication | `Org` object holds the API session | `WebexSimpleApi` holds the token |
|
|
1146
|
+
|
|
1147
|
+
### Device Management Comparison
|
|
1148
|
+
|
|
1149
|
+
```python
|
|
1150
|
+
# wxcadm — object-oriented
|
|
1151
|
+
device = workspace.devices.get(mac_address="AABBCCDDEEFF")
|
|
1152
|
+
device.settings = new_settings
|
|
1153
|
+
device.apply_changes()
|
|
1154
|
+
|
|
1155
|
+
# wxc_sdk — functional
|
|
1156
|
+
api = WebexSimpleApi(tokens=token)
|
|
1157
|
+
devices = api.devices.list(workspace_id=ws_id)
|
|
1158
|
+
device = next(d for d in devices if d.mac == "AABBCCDDEEFF")
|
|
1159
|
+
api.telephony.devices.update_settings(device_id=device.device_id, settings=new_settings)
|
|
1160
|
+
api.telephony.devices.apply_changes(device_id=device.device_id)
|
|
1161
|
+
```
|
|
1162
|
+
|
|
1163
|
+
### Workspace Comparison
|
|
1164
|
+
|
|
1165
|
+
```python
|
|
1166
|
+
# wxcadm — create workspace with calling
|
|
1167
|
+
ws = org.workspaces.create(
|
|
1168
|
+
location=location, name="Lobby", extension="8100",
|
|
1169
|
+
license_type="workspace"
|
|
1170
|
+
)
|
|
1171
|
+
# License selection is automatic
|
|
1172
|
+
|
|
1173
|
+
# wxc_sdk — more manual steps
|
|
1174
|
+
ws = api.workspaces.create(settings=WorkspaceSettings(...))
|
|
1175
|
+
# License assignment often separate or embedded in settings
|
|
1176
|
+
```
|
|
1177
|
+
|
|
1178
|
+
### Key Differences for Device/Workspace Operations
|
|
1179
|
+
|
|
1180
|
+
| Operation | wxcadm | wxc_sdk |
|
|
1181
|
+
|---|---|---|
|
|
1182
|
+
| List supported devices | `org.devices.supported_devices` | `api.telephony.supported_devices()` |
|
|
1183
|
+
| Create device (activation code) | `workspace.devices.create(model=m)` | `api.devices.create_by_activation_code(...)` |
|
|
1184
|
+
| Get device members/lines | `device.members` (property) | `api.telephony.devices.members(device_id=...)` |
|
|
1185
|
+
| Add shared line | `device.members.add(person)` | `api.telephony.devices.update_members(device_id=..., members=[...])` |
|
|
1186
|
+
| Create DECT network | `dect_list.create(name=..., model=...)` | `api.telephony.dect_devices.create_dect_network(...)` |
|
|
1187
|
+
| Virtual line CRUD | `org.virtual_lines.create(...)` / `vl.update(...)` / `vl.delete()` | `api.telephony.virtual_lines.create(...)` / `.update(...)` / `.delete(...)` |
|
|
1188
|
+
|
|
1189
|
+
### When to Use Which
|
|
1190
|
+
|
|
1191
|
+
- **wxcadm**: Better for scripts that navigate the object graph (org -> location -> workspace -> device -> members). The stateful design means fewer IDs to track.
|
|
1192
|
+
- **wxc_sdk**: Better for targeted API operations when you already have IDs, or when you need access to newer API endpoints that wxcadm may not yet wrap. Also has Pydantic validation on inputs.
|
|
1193
|
+
|
|
1194
|
+
---
|
|
1195
|
+
|
|
1196
|
+
## Common Patterns
|
|
1197
|
+
|
|
1198
|
+
### Provision a Workspace with a Phone
|
|
1199
|
+
|
|
1200
|
+
```python
|
|
1201
|
+
import wxcadm
|
|
1202
|
+
|
|
1203
|
+
org = wxcadm.Org(access_token="...")
|
|
1204
|
+
location = org.locations.get(name="Headquarters")
|
|
1205
|
+
|
|
1206
|
+
# 1. Create workspace
|
|
1207
|
+
ws = org.workspaces.create(
|
|
1208
|
+
location=location,
|
|
1209
|
+
name="Conference Room B",
|
|
1210
|
+
extension="8150",
|
|
1211
|
+
type="meetingRoom",
|
|
1212
|
+
license_type="workspace"
|
|
1213
|
+
)
|
|
1214
|
+
|
|
1215
|
+
# 2. Get the supported device model
|
|
1216
|
+
model = org.devices.supported_devices.get("Cisco 8845")
|
|
1217
|
+
|
|
1218
|
+
# 3. Create device with activation code
|
|
1219
|
+
result = ws.devices.create(model=model)
|
|
1220
|
+
print(f"Activation Code: {result['activation_code']}")
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
### Add a Shared Line Appearance
|
|
1224
|
+
|
|
1225
|
+
```python
|
|
1226
|
+
device = person.devices[0]
|
|
1227
|
+
target_workspace = org.workspaces.get(name="Lobby Phone")
|
|
1228
|
+
|
|
1229
|
+
device.members.add(
|
|
1230
|
+
target_workspace,
|
|
1231
|
+
line_type="shared",
|
|
1232
|
+
line_label="Lobby"
|
|
1233
|
+
)
|
|
1234
|
+
device.apply_changes()
|
|
1235
|
+
```
|
|
1236
|
+
|
|
1237
|
+
### Set Up a DECT Network
|
|
1238
|
+
|
|
1239
|
+
```python
|
|
1240
|
+
location = org.locations.get(name="Warehouse")
|
|
1241
|
+
dect_list = DECTNetworkList(org, location=location)
|
|
1242
|
+
|
|
1243
|
+
# Create network
|
|
1244
|
+
network = dect_list.create(
|
|
1245
|
+
name="Warehouse DECT",
|
|
1246
|
+
model="DBS210",
|
|
1247
|
+
default_access_code="5678",
|
|
1248
|
+
location=location
|
|
1249
|
+
)
|
|
1250
|
+
|
|
1251
|
+
# Add base stations
|
|
1252
|
+
network.add_base_stations(["AABBCCDDEEFF", "112233445566"])
|
|
1253
|
+
|
|
1254
|
+
# Add a handset
|
|
1255
|
+
warehouse_ws = org.workspaces.get(name="Warehouse Floor")
|
|
1256
|
+
network.add_handset(
|
|
1257
|
+
display_name="Floor 1",
|
|
1258
|
+
line1=warehouse_ws
|
|
1259
|
+
)
|
|
1260
|
+
```
|
|
1261
|
+
|
|
1262
|
+
### Bulk Number Add and Virtual Line Creation
|
|
1263
|
+
|
|
1264
|
+
```python
|
|
1265
|
+
location = org.locations.get(name="Branch Office")
|
|
1266
|
+
|
|
1267
|
+
# Add numbers to the location (Local Gateway/Non-integrated PSTN only)
|
|
1268
|
+
org.numbers.add(
|
|
1269
|
+
location=location,
|
|
1270
|
+
numbers=["+15559990001", "+15559990002"]
|
|
1271
|
+
)
|
|
1272
|
+
|
|
1273
|
+
# Create a virtual line with one of the new numbers
|
|
1274
|
+
vl = org.virtual_lines.create(
|
|
1275
|
+
first_name="Reception",
|
|
1276
|
+
last_name="Line",
|
|
1277
|
+
phone_number="+15559990001",
|
|
1278
|
+
extension="9001",
|
|
1279
|
+
location=location
|
|
1280
|
+
)
|
|
1281
|
+
vl.refresh_config()
|
|
1282
|
+
|
|
1283
|
+
# Assign to a device as a shared line
|
|
1284
|
+
device = org.devices.get(mac_address="FFEEDDCCBBAA")
|
|
1285
|
+
device.members.add(vl, line_type="shared", line_label="Reception")
|
|
1286
|
+
```
|
|
1287
|
+
|
|
1288
|
+
---
|
|
1289
|
+
|
|
1290
|
+
## Gotchas
|
|
1291
|
+
|
|
1292
|
+
- **VirtualLine.get_call_recording() is broken.** The source passes `'get'` as the first positional argument to `self.org.api.get()`, where the first parameter is `endpoint`. The actual URL ends up as `params`. Use raw HTTP instead: `GET /v1/telephony/config/virtualLines/{id}/callRecording`.
|
|
1293
|
+
- **VirtualLine.delete() returns False on success.** Confirmed bug — the source explicitly `return False` after a successful API call, while other `delete()` methods return `True`.
|
|
1294
|
+
- **VirtualLine.create() returns a sparse object.** The returned instance only has `id` populated. Call `vl.refresh_config()` to populate all fields before accessing other attributes.
|
|
1295
|
+
- **DECTNetworkList has three access patterns.** Both `org.dect_networks` and `location.dect_networks` property accessors exist (lazy-loaded), and direct instantiation (`DECTNetworkList(org, location=location)`) also works.
|
|
1296
|
+
- **Workspace.unassign_wxc() only works for collaboration devices.** Phone-based workspaces (`supportedDevices="phones"`) cannot have WxC unassigned — they must be deleted and recreated.
|
|
1297
|
+
- **wxc_sdk DECT method name corrected.** The DECT network creation method is `api.telephony.dect_devices.create_dect_network(...)`, not `create_network()`. Virtual line methods (`api.telephony.virtual_lines.create/update/delete`) are correct as documented.
|
|
1298
|
+
|
|
1299
|
+
---
|
|
1300
|
+
|
|
1301
|
+
## See Also
|
|
1302
|
+
|
|
1303
|
+
- [devices-core.md](devices-core.md) — wxc_sdk device management APIs (listing, creation, configuration, members)
|
|
1304
|
+
- [devices-dect.md](devices-dect.md) — wxc_sdk DECT network management for comparison with wxcadm's `DECTNetworkList`
|
|
1305
|
+
- [devices-workspaces.md](devices-workspaces.md) — wxc_sdk workspace device provisioning and workspace call settings
|