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,2541 @@
|
|
|
1
|
+
# Additional Call Features Reference
|
|
2
|
+
|
|
3
|
+
## Sources
|
|
4
|
+
|
|
5
|
+
- wxc_sdk v1.30.0
|
|
6
|
+
- OpenAPI spec: specs/webex-cloud-calling.json
|
|
7
|
+
- developer.webex.com Call Features APIs
|
|
8
|
+
|
|
9
|
+
Comprehensive reference for Webex Calling Paging Groups, Call Park, Call Park Extensions, Call Pickup, Voicemail Groups, Customer Assist (formerly CX Essentials), Operating Modes, Call Recording, Announcements/Playlists, Single Number Reach, and Virtual Extensions using the `wxc_sdk`. Each section includes both SDK signatures and Raw HTTP examples.
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Table of Contents
|
|
14
|
+
|
|
15
|
+
1. [SDK Access Paths](#sdk-access-paths)
|
|
16
|
+
2. [Required Scopes](#required-scopes)
|
|
17
|
+
3. [Paging Groups](#paging-groups)
|
|
18
|
+
4. [Call Park](#call-park)
|
|
19
|
+
5. [Call Park Extensions](#call-park-extensions)
|
|
20
|
+
6. [Call Pickup](#call-pickup)
|
|
21
|
+
7. [Voicemail Groups](#voicemail-groups)
|
|
22
|
+
8. [Customer Assist (CX Essentials)](#customer-assist-cx-essentials)
|
|
23
|
+
9. [Operating Modes](#operating-modes)
|
|
24
|
+
10. [Call Recording (Org-Level)](#call-recording-org-level)
|
|
25
|
+
11. [Announcements & Playlists](#announcements--playlists)
|
|
26
|
+
12. [Single Number Reach](#single-number-reach)
|
|
27
|
+
13. [Virtual Extensions](#virtual-extensions)
|
|
28
|
+
14. [Data Models Quick Reference](#data-models-quick-reference)
|
|
29
|
+
15. [Dependencies & Relationships](#dependencies--relationships)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## SDK Access Paths
|
|
34
|
+
|
|
35
|
+
All features in this document are accessed through the `TelephonyApi` instance:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
from wxc_sdk import WebexSimpleApi
|
|
39
|
+
|
|
40
|
+
api = WebexSimpleApi(tokens='...')
|
|
41
|
+
|
|
42
|
+
api.telephony.paging # PagingApi
|
|
43
|
+
api.telephony.callpark # CallParkApi
|
|
44
|
+
api.telephony.callpark_extension # CallparkExtensionApi
|
|
45
|
+
api.telephony.callpickup # CallPickupApi
|
|
46
|
+
api.telephony.voicemail_groups # VoicemailGroupsApi
|
|
47
|
+
api.telephony.cx_essentials # CustomerExperienceEssentialsApi
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Required Scopes
|
|
53
|
+
|
|
54
|
+
| Operation | Scope |
|
|
55
|
+
|-----------|-------|
|
|
56
|
+
| Read paging groups, call parks, call pickups, call park extensions, voicemail groups | `spark-admin:telephony_config_read` |
|
|
57
|
+
| Create/update/delete paging groups, call parks, call pickups, call park extensions, voicemail groups | `spark-admin:telephony_config_write` |
|
|
58
|
+
| Read Customer Assist queue recording | `spark-admin:people_read` |
|
|
59
|
+
| Configure Customer Assist queue recording | `spark-admin:people_write` |
|
|
60
|
+
| Read Customer Assist wrap-up reasons, screen pop, available agents | `spark-admin:telephony_config_read` |
|
|
61
|
+
| Modify Customer Assist wrap-up reasons, screen pop | `spark-admin:telephony_config_write` |
|
|
62
|
+
|
|
63
|
+
All APIs accept an optional `org_id` parameter, allowing partner administrators to operate on a customer organization.
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Paging Groups
|
|
68
|
+
|
|
69
|
+
### Overview
|
|
70
|
+
|
|
71
|
+
Group Paging allows a person to place a **one-way call or group page** to up to **75 people and/or workspaces** by dialing a number or extension assigned to a specific paging group. The paging service makes a simultaneous call to all assigned targets.
|
|
72
|
+
|
|
73
|
+
Use cases: overhead announcements, warehouse pages, emergency notifications to a group of phones.
|
|
74
|
+
|
|
75
|
+
### SDK API Class
|
|
76
|
+
|
|
77
|
+
```python
|
|
78
|
+
class PagingApi(ApiChild, base='telephony/config')
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### API Operations
|
|
82
|
+
|
|
83
|
+
#### List Paging Groups
|
|
84
|
+
|
|
85
|
+
Returns all paging groups across the organization (or filtered by location).
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
def list(
|
|
89
|
+
self,
|
|
90
|
+
location_id: str = None,
|
|
91
|
+
name: str = None,
|
|
92
|
+
phone_number: str = None,
|
|
93
|
+
org_id: str = None,
|
|
94
|
+
**params
|
|
95
|
+
) -> Generator[Paging, None, None]
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- `location_id`: Filter to a specific location. Default is all locations.
|
|
99
|
+
- `name`: Filter by matching name.
|
|
100
|
+
- `phone_number`: Filter by matching primary phone number or extension.
|
|
101
|
+
- Returns paginated results with item key `locationPaging`.
|
|
102
|
+
|
|
103
|
+
#### Get Paging Group Details
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
def details(
|
|
107
|
+
self,
|
|
108
|
+
location_id: str,
|
|
109
|
+
paging_id: str,
|
|
110
|
+
org_id: str = None
|
|
111
|
+
) -> Paging
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Returns the full `Paging` object including `originators` and `targets` with detailed agent info (first/last name, phone number, extension, type).
|
|
115
|
+
|
|
116
|
+
#### Create Paging Group
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
def create(
|
|
120
|
+
self,
|
|
121
|
+
location_id: str,
|
|
122
|
+
settings: Paging,
|
|
123
|
+
org_id: str = None
|
|
124
|
+
) -> str # returns new paging group ID
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
**Validation rule**: If `originators` are provided, `originator_caller_id_enabled` is **required** (raises `TypeError` otherwise).
|
|
128
|
+
|
|
129
|
+
Convenience factory:
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
settings = Paging.create(name='Warehouse Page', extension='8100')
|
|
133
|
+
paging_id = api.telephony.paging.create(location_id=loc_id, settings=settings)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
#### Update Paging Group
|
|
137
|
+
|
|
138
|
+
```python
|
|
139
|
+
def update(
|
|
140
|
+
self,
|
|
141
|
+
location_id: str,
|
|
142
|
+
update: Paging,
|
|
143
|
+
paging_id: str,
|
|
144
|
+
org_id: str = None
|
|
145
|
+
) -> None
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### Delete Paging Group
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
def delete_paging(
|
|
152
|
+
self,
|
|
153
|
+
location_id: str,
|
|
154
|
+
paging_id: str,
|
|
155
|
+
org_id: str = None
|
|
156
|
+
) -> None
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
#### Get Available Phone Numbers
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
def primary_available_phone_numbers(
|
|
163
|
+
self,
|
|
164
|
+
location_id: str,
|
|
165
|
+
phone_number: List[str] = None,
|
|
166
|
+
org_id: str = None,
|
|
167
|
+
**params
|
|
168
|
+
) -> Generator[AvailableNumber, None, None]
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
Lists service and standard numbers available for assignment as the paging group's primary phone number. Numbers are associated with the specified location, can be active or inactive, and must be unassigned.
|
|
172
|
+
|
|
173
|
+
### Key Data Models
|
|
174
|
+
|
|
175
|
+
#### `Paging`
|
|
176
|
+
|
|
177
|
+
| Field | Type | Required for Create | Notes |
|
|
178
|
+
|-------|------|-------------------|-------|
|
|
179
|
+
| `paging_id` | `str` (alias: `id`) | -- | Read-only, set by API |
|
|
180
|
+
| `enabled` | `bool` | No | Default varies |
|
|
181
|
+
| `name` | `str` | **Yes** | Max 30 chars |
|
|
182
|
+
| `phone_number` | `str` | **One of phone_number/extension** | Max 23 chars |
|
|
183
|
+
| `extension` | `str` | **One of phone_number/extension** | 2-10 chars |
|
|
184
|
+
| `toll_free_number` | `bool` | -- | Read-only |
|
|
185
|
+
| `language` | `str` | No | Read-only (use `language_code` for write) |
|
|
186
|
+
| `language_code` | `str` | No | e.g., `en_us` |
|
|
187
|
+
| `originator_caller_id_enabled` | `bool` | **Yes, if originators set** | Shows page originator ID on target caller ID |
|
|
188
|
+
| `originators` | `list[PagingAgent]` | No | People/workspaces who can originate pages |
|
|
189
|
+
| `targets` | `list[PagingAgent]` | No | People/workspaces/virtual lines who receive pages |
|
|
190
|
+
| `first_name` / `last_name` | `str` | No | **Deprecated** -- use `direct_line_caller_id_name` and `dial_by_name` |
|
|
191
|
+
| `direct_line_caller_id_name` | `DirectLineCallerIdName` | No | Replacement for first/last name |
|
|
192
|
+
| `dial_by_name` | `str` | No | Name used for dial-by-name directory |
|
|
193
|
+
|
|
194
|
+
#### `PagingAgent`
|
|
195
|
+
|
|
196
|
+
| Field | Type | Notes |
|
|
197
|
+
|-------|------|-------|
|
|
198
|
+
| `agent_id` (alias: `id`) | `str` | **Only field sent in create/update** |
|
|
199
|
+
| `first_name` | `str` | Read-only (returned from details) |
|
|
200
|
+
| `last_name` | `str` | Read-only |
|
|
201
|
+
| `agent_type` (alias: `type`) | `UserType` | `PEOPLE` or `PLACE` |
|
|
202
|
+
| `phone_number` | `str` | Read-only |
|
|
203
|
+
| `extension` | `str` | Read-only |
|
|
204
|
+
| `routing_prefix` | `str` | Read-only |
|
|
205
|
+
| `esn` | `str` | Read-only (routing prefix + extension) |
|
|
206
|
+
|
|
207
|
+
**Important**: When creating or updating, `originators` and `targets` are serialized as flat lists of IDs only, not full agent objects.
|
|
208
|
+
|
|
209
|
+
### Phone Number / Extension Assignment
|
|
210
|
+
|
|
211
|
+
- Either `phone_number` or `extension` is mandatory (enforced by `Paging.create()` factory).
|
|
212
|
+
- Use `primary_available_phone_numbers()` to find unassigned numbers at a location.
|
|
213
|
+
- The `toll_free_number` flag is read-only and reflects whether the assigned number is toll-free.
|
|
214
|
+
|
|
215
|
+
### Member Management
|
|
216
|
+
|
|
217
|
+
- **Originators**: People/workspaces who can initiate a page. Set via `originators` field as a list of `PagingAgent` with `agent_id` populated.
|
|
218
|
+
- **Targets**: People/workspaces/virtual lines who receive the page broadcast. Set via `targets` field. Up to 75 targets.
|
|
219
|
+
- On create/update, pass agent IDs only. On read (details), full agent info is returned.
|
|
220
|
+
|
|
221
|
+
### Raw HTTP
|
|
222
|
+
|
|
223
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
224
|
+
|
|
225
|
+
```python
|
|
226
|
+
from wxc_sdk import WebexSimpleApi
|
|
227
|
+
api = WebexSimpleApi()
|
|
228
|
+
BASE = "https://webexapis.com/v1"
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
**List Paging Groups** (org-wide, filterable by location):
|
|
232
|
+
|
|
233
|
+
```python
|
|
234
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/paging",
|
|
235
|
+
params={"locationId": loc_id, "name": "Warehouse", "max": 1000})
|
|
236
|
+
items = result["paging"] # response key: "paging"
|
|
237
|
+
# Each item: {id, name, extension, phoneNumber, enabled, locationId, locationName, routingPrefix, esn, tollFreeNumber}
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
**Get Paging Group Details:**
|
|
241
|
+
|
|
242
|
+
```python
|
|
243
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/paging/{paging_id}")
|
|
244
|
+
# Returns full object including originators[], targets[] with firstName, lastName, type, phoneNumber, extension
|
|
245
|
+
```
|
|
246
|
+
|
|
247
|
+
**Create Paging Group** -- required: `name`, one of `phoneNumber`/`extension`:
|
|
248
|
+
|
|
249
|
+
```python
|
|
250
|
+
body = {
|
|
251
|
+
"name": "Warehouse Page",
|
|
252
|
+
"extension": "8100",
|
|
253
|
+
"languageCode": "en_us",
|
|
254
|
+
"originatorCallerIdEnabled": True, # required if originators are set
|
|
255
|
+
"originators": [person_id], # Plain string array, NOT [{"id": person_id}]
|
|
256
|
+
"targets": [person_id, workspace_id] # Plain string array, NOT [{"id": ...}]
|
|
257
|
+
}
|
|
258
|
+
# IMPORTANT: targets and originators are arrays of ID strings, not objects.
|
|
259
|
+
# [{"id": ...}] returns 400 "Invalid field value". Verified via stress test 2026-03-25.
|
|
260
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/paging", json=body)
|
|
261
|
+
paging_id = result["id"]
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
**Update Paging Group:**
|
|
265
|
+
|
|
266
|
+
```python
|
|
267
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/paging/{paging_id}",
|
|
268
|
+
json={"name": "Updated Name", "enabled": True})
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
**Delete Paging Group:**
|
|
272
|
+
|
|
273
|
+
```python
|
|
274
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/paging/{paging_id}")
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
**Get Available Phone Numbers:**
|
|
278
|
+
|
|
279
|
+
```python
|
|
280
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/paging/availableNumbers",
|
|
281
|
+
params={"max": 1000})
|
|
282
|
+
items = result["availableNumbers"]
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
### CLI Examples
|
|
286
|
+
|
|
287
|
+
```bash
|
|
288
|
+
# List all paging groups (org-wide)
|
|
289
|
+
wxcli paging-group list
|
|
290
|
+
|
|
291
|
+
# List paging groups filtered by location
|
|
292
|
+
wxcli paging-group list --location-id <loc_id>
|
|
293
|
+
|
|
294
|
+
# Get details for a specific paging group
|
|
295
|
+
wxcli paging-group show --location-id <loc_id> --paging-group-id <pg_id>
|
|
296
|
+
|
|
297
|
+
# Create a paging group
|
|
298
|
+
wxcli paging-group create --location-id <loc_id> --name "Warehouse Page" --extension "8100"
|
|
299
|
+
|
|
300
|
+
# Update a paging group
|
|
301
|
+
wxcli paging-group update --location-id <loc_id> --paging-group-id <pg_id> --name "Updated Page"
|
|
302
|
+
|
|
303
|
+
# Delete a paging group
|
|
304
|
+
wxcli paging-group delete --location-id <loc_id> --paging-group-id <pg_id>
|
|
305
|
+
|
|
306
|
+
# List available phone numbers for paging group assignment
|
|
307
|
+
wxcli paging-group list-available-numbers --location-id <loc_id>
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Call Park
|
|
313
|
+
|
|
314
|
+
### Overview
|
|
315
|
+
|
|
316
|
+
Call Park allows a call recipient to place a call **on hold at a designated park location** so it can be retrieved from another device. Users park calls against extensions or Call Park Extensions, then other users retrieve them by dialing the park extension.
|
|
317
|
+
|
|
318
|
+
Use cases: front-desk parks a call, employee picks it up from their desk phone; warehouse environments where users move between stations.
|
|
319
|
+
|
|
320
|
+
### SDK API Class
|
|
321
|
+
|
|
322
|
+
```python
|
|
323
|
+
class CallParkApi(ApiChild, base='telephony/config/callParks')
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
### API Operations
|
|
327
|
+
|
|
328
|
+
#### List Call Parks
|
|
329
|
+
|
|
330
|
+
```python
|
|
331
|
+
def list(
|
|
332
|
+
self,
|
|
333
|
+
location_id: str,
|
|
334
|
+
order: str = None, # 'ASC' or 'DSC'
|
|
335
|
+
name: str = None, # filter by name (max 80 chars)
|
|
336
|
+
org_id: str = None,
|
|
337
|
+
**params
|
|
338
|
+
) -> Generator[CallPark, None, None]
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
**NOTE**: The Call Park ID will change upon modification of the Call Park name.
|
|
342
|
+
|
|
343
|
+
#### Get Call Park Details
|
|
344
|
+
|
|
345
|
+
```python
|
|
346
|
+
def details(
|
|
347
|
+
self,
|
|
348
|
+
location_id: str,
|
|
349
|
+
callpark_id: str,
|
|
350
|
+
org_id: str = None
|
|
351
|
+
) -> CallPark
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
#### Create Call Park
|
|
355
|
+
|
|
356
|
+
```python
|
|
357
|
+
def create(
|
|
358
|
+
self,
|
|
359
|
+
location_id: str,
|
|
360
|
+
settings: CallPark,
|
|
361
|
+
org_id: str = None
|
|
362
|
+
) -> str # returns new call park ID
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
Convenience factory (minimal call park with recall to parking user only):
|
|
366
|
+
|
|
367
|
+
```python
|
|
368
|
+
settings = CallPark.default(name='Lobby Park')
|
|
369
|
+
park_id = api.telephony.callpark.create(location_id=loc_id, settings=settings)
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
#### Update Call Park
|
|
373
|
+
|
|
374
|
+
```python
|
|
375
|
+
def update(
|
|
376
|
+
self,
|
|
377
|
+
location_id: str,
|
|
378
|
+
callpark_id: str,
|
|
379
|
+
settings: CallPark,
|
|
380
|
+
org_id: str = None
|
|
381
|
+
) -> str # returns updated call park ID
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
**NOTE**: The Call Park ID changes when the name is modified. The returned ID is the new one.
|
|
385
|
+
|
|
386
|
+
#### Delete Call Park
|
|
387
|
+
|
|
388
|
+
```python
|
|
389
|
+
def delete_callpark(
|
|
390
|
+
self,
|
|
391
|
+
location_id: str,
|
|
392
|
+
callpark_id: str,
|
|
393
|
+
org_id: str = None
|
|
394
|
+
) -> None
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
#### Get Available Agents
|
|
398
|
+
|
|
399
|
+
```python
|
|
400
|
+
def available_agents(
|
|
401
|
+
self,
|
|
402
|
+
location_id: str,
|
|
403
|
+
call_park_name: str = None,
|
|
404
|
+
name: str = None,
|
|
405
|
+
phone_number: str = None,
|
|
406
|
+
order: str = None,
|
|
407
|
+
org_id: str = None,
|
|
408
|
+
**params
|
|
409
|
+
) -> Generator[PersonPlaceAgent, None, None]
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Returns people and workspaces eligible to be added as call park agents. Sort fields: `fname`, `lname`, `number`, `extension` (pipe-separated, max 3).
|
|
413
|
+
|
|
414
|
+
#### Get Available Recall Hunt Groups
|
|
415
|
+
|
|
416
|
+
```python
|
|
417
|
+
def available_recalls(
|
|
418
|
+
self,
|
|
419
|
+
location_id: str,
|
|
420
|
+
name: str = None,
|
|
421
|
+
order: str = None,
|
|
422
|
+
org_id: str = None,
|
|
423
|
+
**params
|
|
424
|
+
) -> Generator[AvailableRecallHuntGroup, None, None]
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
Lists hunt groups that can be used as recall destinations.
|
|
428
|
+
|
|
429
|
+
#### Get Location Call Park Settings
|
|
430
|
+
|
|
431
|
+
```python
|
|
432
|
+
def call_park_settings(
|
|
433
|
+
self,
|
|
434
|
+
location_id: str,
|
|
435
|
+
org_id: str = None
|
|
436
|
+
) -> LocationCallParkSettings
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
#### Update Location Call Park Settings
|
|
440
|
+
|
|
441
|
+
```python
|
|
442
|
+
def update_call_park_settings(
|
|
443
|
+
self,
|
|
444
|
+
location_id: str,
|
|
445
|
+
settings: LocationCallParkSettings,
|
|
446
|
+
org_id: str = None
|
|
447
|
+
) -> None
|
|
448
|
+
```
|
|
449
|
+
|
|
450
|
+
### Key Data Models
|
|
451
|
+
|
|
452
|
+
#### `CallPark`
|
|
453
|
+
|
|
454
|
+
| Field | Type | Notes |
|
|
455
|
+
|-------|------|-------|
|
|
456
|
+
| `callpark_id` (alias: `id`) | `str` | Read-only. **Changes when name is modified.** |
|
|
457
|
+
| `name` | `str` | Max 80 chars |
|
|
458
|
+
| `location_name` | `str` | Read-only |
|
|
459
|
+
| `location_id` | `str` | Read-only |
|
|
460
|
+
| `recall` | `RecallHuntGroup` | Recall options (who gets alerted when park times out) |
|
|
461
|
+
| `agents` | `list[PersonPlaceAgent]` | People/workspaces eligible to receive parked calls |
|
|
462
|
+
| `park_on_agents_enabled` | `bool` | Whether calls can be parked on agents as a destination |
|
|
463
|
+
| `call_park_extensions` | `list[CallParkExtension]` | Park extensions assigned to this call park |
|
|
464
|
+
|
|
465
|
+
**Important**: On create/update, `agents` and `call_park_extensions` are serialized as flat lists of IDs only.
|
|
466
|
+
|
|
467
|
+
#### `RecallHuntGroup`
|
|
468
|
+
|
|
469
|
+
| Field | Type | Notes |
|
|
470
|
+
|-------|------|-------|
|
|
471
|
+
| `hunt_group_id` | `str` | Hunt group ID for recall alternate destination |
|
|
472
|
+
| `hunt_group_name` | `str` | Read-only (excluded from create/update) |
|
|
473
|
+
| `option` | `CallParkRecall` | Recall behavior enum |
|
|
474
|
+
|
|
475
|
+
#### `CallParkRecall` (Enum)
|
|
476
|
+
|
|
477
|
+
| Value | Constant | Description |
|
|
478
|
+
|-------|----------|-------------|
|
|
479
|
+
| `ALERT_PARKING_USER_ONLY` | `parking_user_only` | Alert only the user who parked the call |
|
|
480
|
+
| `ALERT_PARKING_USER_FIRST_THEN_HUNT_GROUP` | `parking_user_first_then_hunt_group` | Alert parking user first, then hunt group |
|
|
481
|
+
| `ALERT_HUNT_GROUP_ONLY` | `hunt_group_only` | Alert hunt group only |
|
|
482
|
+
|
|
483
|
+
#### `CallParkSettings` (Location-Level)
|
|
484
|
+
|
|
485
|
+
| Field | Type | Default | Notes |
|
|
486
|
+
|-------|------|---------|-------|
|
|
487
|
+
| `ring_pattern` | `RingPattern` | `normal` | Ring pattern when park extension is called |
|
|
488
|
+
| `recall_time` | `int` | `45` | Seconds before recall (30-600 range) |
|
|
489
|
+
| `hunt_wait_time` | `int` | `45` | Seconds before reverting to hunt group (30-600 range) |
|
|
490
|
+
|
|
491
|
+
#### `LocationCallParkSettings`
|
|
492
|
+
|
|
493
|
+
Wraps `call_park_recall` (`RecallHuntGroup`) and `call_park_settings` (`CallParkSettings`) into a single object for location-level configuration.
|
|
494
|
+
|
|
495
|
+
### Phone Number / Extension Assignment
|
|
496
|
+
|
|
497
|
+
Call Parks themselves do not have phone numbers or extensions directly. They are groups of agents and park extensions. Calls are parked **to** a Call Park Extension (see next section) or to an agent's extension.
|
|
498
|
+
|
|
499
|
+
### Member Management
|
|
500
|
+
|
|
501
|
+
- **Agents**: People and workspaces eligible to receive parked calls. Added via the `agents` field (list of IDs on create/update).
|
|
502
|
+
- **Call Park Extensions**: Dedicated extensions for parking. Added via `call_park_extensions` field (list of IDs on create/update).
|
|
503
|
+
- Use `available_agents()` to discover eligible agents at a location.
|
|
504
|
+
- Use `available_recalls()` to discover hunt groups eligible as recall destinations.
|
|
505
|
+
|
|
506
|
+
### Raw HTTP
|
|
507
|
+
|
|
508
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
509
|
+
|
|
510
|
+
```python
|
|
511
|
+
from wxc_sdk import WebexSimpleApi
|
|
512
|
+
api = WebexSimpleApi()
|
|
513
|
+
BASE = "https://webexapis.com/v1"
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
**List Call Parks** (location-scoped):
|
|
517
|
+
|
|
518
|
+
```python
|
|
519
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParks",
|
|
520
|
+
params={"name": "Lobby", "order": "ASC", "max": 1000})
|
|
521
|
+
items = result["callParks"] # response key: "callParks"
|
|
522
|
+
# Each item: {id, name}
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
**Get Call Park Details:**
|
|
526
|
+
|
|
527
|
+
```python
|
|
528
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParks/{park_id}")
|
|
529
|
+
# Returns: name, recall, agents[], callParkExtensions[], parkOnAgentsEnabled
|
|
530
|
+
```
|
|
531
|
+
|
|
532
|
+
**Create Call Park** -- required: `name`, `recall` with `option`:
|
|
533
|
+
|
|
534
|
+
```python
|
|
535
|
+
body = {
|
|
536
|
+
"name": "Lobby Park",
|
|
537
|
+
"recall": {"option": "ALERT_PARKING_USER_ONLY"}, # required
|
|
538
|
+
"parkOnAgentsEnabled": True,
|
|
539
|
+
"agents": [{"id": person_id}],
|
|
540
|
+
"callParkExtensions": [{"id": cpe_id}]
|
|
541
|
+
}
|
|
542
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/callParks", json=body)
|
|
543
|
+
park_id = result["id"]
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
**Update Call Park** (ID changes when name changes):
|
|
547
|
+
|
|
548
|
+
```python
|
|
549
|
+
result = api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/callParks/{park_id}",
|
|
550
|
+
json={"name": "New Name", "parkOnAgentsEnabled": False})
|
|
551
|
+
# New park_id returned if name changed
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
**Delete Call Park:**
|
|
555
|
+
|
|
556
|
+
```python
|
|
557
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/callParks/{park_id}")
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Get Available Agents:**
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParks/availableUsers",
|
|
564
|
+
params={"name": "John", "max": 1000})
|
|
565
|
+
items = result["availableUsers"] # response key: "availableUsers"
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
**Get Available Recall Hunt Groups:**
|
|
569
|
+
|
|
570
|
+
```python
|
|
571
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParks/availableRecallHuntGroups",
|
|
572
|
+
params={"max": 1000})
|
|
573
|
+
items = result["availableRecallHuntGroups"]
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
**Get Location Call Park Settings:**
|
|
577
|
+
|
|
578
|
+
```python
|
|
579
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParks/settings")
|
|
580
|
+
# Returns: callParkRecall, callParkSettings (ringPattern, recallTime, huntWaitTime)
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
**Update Location Call Park Settings:**
|
|
584
|
+
|
|
585
|
+
```python
|
|
586
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/callParks/settings",
|
|
587
|
+
json={"callParkSettings": {"recallTime": 60, "huntWaitTime": 60}})
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
### CLI Examples
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
# List call parks at a location
|
|
594
|
+
wxcli call-park list --location-id <loc_id>
|
|
595
|
+
|
|
596
|
+
# Get details for a call park
|
|
597
|
+
wxcli call-park show --location-id <loc_id> --call-park-id <park_id>
|
|
598
|
+
|
|
599
|
+
# Create a call park
|
|
600
|
+
wxcli call-park create --location-id <loc_id> --name "Lobby Park" --json-body '{"recall": {"option": "ALERT_PARKING_USER_ONLY"}}'
|
|
601
|
+
|
|
602
|
+
# Update a call park
|
|
603
|
+
wxcli call-park update --location-id <loc_id> --call-park-id <park_id> --name "New Park Name"
|
|
604
|
+
|
|
605
|
+
# Delete a call park
|
|
606
|
+
wxcli call-park delete --location-id <loc_id> --call-park-id <park_id>
|
|
607
|
+
|
|
608
|
+
# List available agents for call park
|
|
609
|
+
wxcli call-park list-available-users --location-id <loc_id>
|
|
610
|
+
|
|
611
|
+
# List available recall hunt groups
|
|
612
|
+
wxcli call-park list-available-recall-hunt-groups --location-id <loc_id>
|
|
613
|
+
|
|
614
|
+
# Get location-level call park settings
|
|
615
|
+
wxcli call-park show-settings --location-id <loc_id>
|
|
616
|
+
|
|
617
|
+
# Update location-level call park settings
|
|
618
|
+
wxcli call-park update-settings --location-id <loc_id> --json-body '{"callParkSettings": {"recallTime": 60}}'
|
|
619
|
+
```
|
|
620
|
+
|
|
621
|
+
---
|
|
622
|
+
|
|
623
|
+
## Call Park Extensions
|
|
624
|
+
|
|
625
|
+
### Overview
|
|
626
|
+
|
|
627
|
+
Call Park Extensions are **dedicated extensions defined within the Call Park service** for holding parked calls. A user parks a call to one of these extensions, and another user retrieves it by dialing that extension. Call Park Extensions can also be added as **monitored lines** on Cisco phones, so users can park and retrieve calls by pressing a line key.
|
|
628
|
+
|
|
629
|
+
The Call Park service is enabled for all users by default.
|
|
630
|
+
|
|
631
|
+
### SDK API Class
|
|
632
|
+
|
|
633
|
+
```python
|
|
634
|
+
class CallparkExtensionApi(ApiChild, base='telephony')
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
### API Operations
|
|
638
|
+
|
|
639
|
+
#### List Call Park Extensions
|
|
640
|
+
|
|
641
|
+
```python
|
|
642
|
+
def list(
|
|
643
|
+
self,
|
|
644
|
+
extension: str = None,
|
|
645
|
+
name: str = None,
|
|
646
|
+
location_id: str = None,
|
|
647
|
+
location_name: str = None,
|
|
648
|
+
order: str = None,
|
|
649
|
+
org_id: str = None,
|
|
650
|
+
**params
|
|
651
|
+
) -> Generator[CallParkExtension, None, None]
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
Lists across all locations if `location_id` is not specified. Sort fields: `groupName`, `callParkExtension`, `callParkExtensionName`, `callParkExtensionExternalId`.
|
|
655
|
+
|
|
656
|
+
#### Get Call Park Extension Details
|
|
657
|
+
|
|
658
|
+
```python
|
|
659
|
+
def details(
|
|
660
|
+
self,
|
|
661
|
+
location_id: str,
|
|
662
|
+
cpe_id: str,
|
|
663
|
+
org_id: str = None
|
|
664
|
+
) -> CallParkExtension
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
Returns `CallParkExtension` with `name` and `extension` fields.
|
|
668
|
+
|
|
669
|
+
#### Create Call Park Extension
|
|
670
|
+
|
|
671
|
+
```python
|
|
672
|
+
def create(
|
|
673
|
+
self,
|
|
674
|
+
location_id: str,
|
|
675
|
+
name: str, # max 30 chars
|
|
676
|
+
extension: str, # 2-10 chars, must be unique
|
|
677
|
+
org_id: str = None
|
|
678
|
+
) -> str # returns new call park extension ID
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
#### Update Call Park Extension
|
|
682
|
+
|
|
683
|
+
```python
|
|
684
|
+
def update(
|
|
685
|
+
self,
|
|
686
|
+
location_id: str,
|
|
687
|
+
cpe_id: str,
|
|
688
|
+
name: str = None,
|
|
689
|
+
extension: str = None,
|
|
690
|
+
org_id: str = None
|
|
691
|
+
) -> None
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Both `name` and `extension` are optional -- only the provided fields are updated.
|
|
695
|
+
|
|
696
|
+
#### Delete Call Park Extension
|
|
697
|
+
|
|
698
|
+
```python
|
|
699
|
+
def delete(
|
|
700
|
+
self,
|
|
701
|
+
location_id: str,
|
|
702
|
+
cpe_id: str,
|
|
703
|
+
org_id: str = None
|
|
704
|
+
) -> None
|
|
705
|
+
```
|
|
706
|
+
|
|
707
|
+
### Key Data Models
|
|
708
|
+
|
|
709
|
+
#### `CallParkExtension` (from `wxc_sdk.common`)
|
|
710
|
+
|
|
711
|
+
| Field | Type | Notes |
|
|
712
|
+
|-------|------|-------|
|
|
713
|
+
| `cpe_id` (alias: `id`) | `str` | Unique identifier |
|
|
714
|
+
| `name` | `str` | Max 30 chars |
|
|
715
|
+
| `extension` | `str` | 2-10 chars, must be unique within location |
|
|
716
|
+
|
|
717
|
+
This is a lightweight model -- just a name and extension. The `CallParkExtension` model is shared from `wxc_sdk.common` and also used within the `CallPark` model to list assigned park extensions.
|
|
718
|
+
|
|
719
|
+
### Phone Number / Extension Assignment
|
|
720
|
+
|
|
721
|
+
- Each Call Park Extension has a **unique extension** within its location.
|
|
722
|
+
- No phone number assignment -- these are extension-only entities.
|
|
723
|
+
- Extensions are dialed internally to park or retrieve calls.
|
|
724
|
+
|
|
725
|
+
### Member Management
|
|
726
|
+
|
|
727
|
+
Call Park Extensions do not have members. They are simple extension holders assigned to Call Park groups (see the `call_park_extensions` field on `CallPark`).
|
|
728
|
+
|
|
729
|
+
### Raw HTTP
|
|
730
|
+
|
|
731
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
732
|
+
|
|
733
|
+
```python
|
|
734
|
+
from wxc_sdk import WebexSimpleApi
|
|
735
|
+
api = WebexSimpleApi()
|
|
736
|
+
BASE = "https://webexapis.com/v1"
|
|
737
|
+
```
|
|
738
|
+
|
|
739
|
+
**List Call Park Extensions** (org-wide, filterable by location):
|
|
740
|
+
|
|
741
|
+
```python
|
|
742
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/callParkExtensions",
|
|
743
|
+
params={"locationId": loc_id, "name": "Park", "max": 1000})
|
|
744
|
+
items = result["callParkExtensions"] # response key: "callParkExtensions"
|
|
745
|
+
# Each item: {id, name, extension, locationId, locationName}
|
|
746
|
+
```
|
|
747
|
+
|
|
748
|
+
**Get Call Park Extension Details:**
|
|
749
|
+
|
|
750
|
+
```python
|
|
751
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callParkExtensions/{cpe_id}")
|
|
752
|
+
# Returns: name, extension
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
**Create Call Park Extension** -- required: `name`, `extension`:
|
|
756
|
+
|
|
757
|
+
```python
|
|
758
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/callParkExtensions",
|
|
759
|
+
json={"name": "Park Slot 1", "extension": "7001"})
|
|
760
|
+
cpe_id = result["id"]
|
|
761
|
+
```
|
|
762
|
+
|
|
763
|
+
**Update Call Park Extension:**
|
|
764
|
+
|
|
765
|
+
```python
|
|
766
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/callParkExtensions/{cpe_id}",
|
|
767
|
+
json={"name": "Park Slot A", "extension": "7002"})
|
|
768
|
+
```
|
|
769
|
+
|
|
770
|
+
**Delete Call Park Extension:**
|
|
771
|
+
|
|
772
|
+
```python
|
|
773
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/callParkExtensions/{cpe_id}")
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
### CLI Examples
|
|
777
|
+
|
|
778
|
+
```bash
|
|
779
|
+
# List call park extensions
|
|
780
|
+
wxcli call-park list-call-park-extensions --location-id <loc_id>
|
|
781
|
+
|
|
782
|
+
# Get details for a call park extension
|
|
783
|
+
wxcli call-park show-call-park-extensions --location-id <loc_id> --call-park-extension-id <cpe_id>
|
|
784
|
+
|
|
785
|
+
# Create a call park extension
|
|
786
|
+
wxcli call-park create-call-park-extensions --location-id <loc_id> --name "Park Slot 1" --extension "7001"
|
|
787
|
+
|
|
788
|
+
# Update a call park extension
|
|
789
|
+
wxcli call-park update-call-park-extensions --location-id <loc_id> --call-park-extension-id <cpe_id> --name "Park Slot A"
|
|
790
|
+
|
|
791
|
+
# Delete a call park extension
|
|
792
|
+
wxcli call-park delete-call-park-extensions --location-id <loc_id> --call-park-extension-id <cpe_id>
|
|
793
|
+
```
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## Call Pickup
|
|
798
|
+
|
|
799
|
+
### Overview
|
|
800
|
+
|
|
801
|
+
Call Pickup enables a user (agent) to **answer any ringing line within their pickup group**. When a call rings unanswered for a configurable period, all members of the pickup group can be notified via audio, visual, or both.
|
|
802
|
+
|
|
803
|
+
Use cases: small offices where team members cover each other's calls; receptionist groups.
|
|
804
|
+
|
|
805
|
+
### SDK API Class
|
|
806
|
+
|
|
807
|
+
```python
|
|
808
|
+
class CallPickupApi(ApiChild, base='telephony/config/callPickups')
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
### API Operations
|
|
812
|
+
|
|
813
|
+
#### List Call Pickups
|
|
814
|
+
|
|
815
|
+
```python
|
|
816
|
+
def list(
|
|
817
|
+
self,
|
|
818
|
+
location_id: str,
|
|
819
|
+
order: Literal['ASC', 'DSC'] = None,
|
|
820
|
+
name: str = None,
|
|
821
|
+
org_id: str = None,
|
|
822
|
+
**params
|
|
823
|
+
) -> Generator[CallPickup, None, None]
|
|
824
|
+
```
|
|
825
|
+
|
|
826
|
+
**NOTE**: The Call Pickup ID will change upon modification of the Call Pickup name.
|
|
827
|
+
|
|
828
|
+
#### Get Call Pickup Details
|
|
829
|
+
|
|
830
|
+
```python
|
|
831
|
+
def details(
|
|
832
|
+
self,
|
|
833
|
+
location_id: str,
|
|
834
|
+
pickup_id: str,
|
|
835
|
+
org_id: str = None
|
|
836
|
+
) -> CallPickup
|
|
837
|
+
```
|
|
838
|
+
|
|
839
|
+
#### Create Call Pickup
|
|
840
|
+
|
|
841
|
+
```python
|
|
842
|
+
def create(
|
|
843
|
+
self,
|
|
844
|
+
location_id: str,
|
|
845
|
+
settings: CallPickup,
|
|
846
|
+
org_id: str = None
|
|
847
|
+
) -> str # returns new call pickup ID
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
#### Update Call Pickup
|
|
851
|
+
|
|
852
|
+
```python
|
|
853
|
+
def update(
|
|
854
|
+
self,
|
|
855
|
+
location_id: str,
|
|
856
|
+
pickup_id: str,
|
|
857
|
+
settings: CallPickup,
|
|
858
|
+
org_id: str = None
|
|
859
|
+
) -> str # returns updated call pickup ID
|
|
860
|
+
```
|
|
861
|
+
|
|
862
|
+
**NOTE**: The Call Pickup ID changes when the name is modified.
|
|
863
|
+
|
|
864
|
+
#### Delete Call Pickup
|
|
865
|
+
|
|
866
|
+
```python
|
|
867
|
+
def delete_pickup(
|
|
868
|
+
self,
|
|
869
|
+
location_id: str,
|
|
870
|
+
pickup_id: str,
|
|
871
|
+
org_id: str = None
|
|
872
|
+
) -> None
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
#### Get Available Agents
|
|
876
|
+
|
|
877
|
+
```python
|
|
878
|
+
def available_agents(
|
|
879
|
+
self,
|
|
880
|
+
location_id: str,
|
|
881
|
+
call_pickup_name: str = None,
|
|
882
|
+
name: str = None,
|
|
883
|
+
phone_number: str = None,
|
|
884
|
+
order: str = None,
|
|
885
|
+
org_id: str = None,
|
|
886
|
+
**params
|
|
887
|
+
) -> Generator[PersonPlaceAgent, None, None]
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
Returns people, workspaces, and virtual lines eligible to be added to pickup groups. Sort fields: `fname`, `lname`, `number`, `extension` (pipe-separated, max 3).
|
|
891
|
+
|
|
892
|
+
### Key Data Models
|
|
893
|
+
|
|
894
|
+
#### `CallPickup`
|
|
895
|
+
|
|
896
|
+
| Field | Type | Notes |
|
|
897
|
+
|-------|------|-------|
|
|
898
|
+
| `pickup_id` (alias: `id`) | `str` | Read-only. **Changes when name is modified.** |
|
|
899
|
+
| `name` | `str` | Max 80 chars |
|
|
900
|
+
| `location_name` | `str` | Read-only |
|
|
901
|
+
| `location_id` | `str` | Read-only |
|
|
902
|
+
| `notification_type` | `PickupNotificationType` | How members are notified of unanswered calls |
|
|
903
|
+
| `notification_delay_timer_seconds` | `int` | Seconds before notification fires |
|
|
904
|
+
| `agents` | `list[PersonPlaceAgent]` | People, workspaces, virtual lines in the group |
|
|
905
|
+
|
|
906
|
+
**Important**: On create/update, `agents` is serialized as a flat list of IDs only.
|
|
907
|
+
|
|
908
|
+
#### `PickupNotificationType` (Enum)
|
|
909
|
+
|
|
910
|
+
| Value | Constant | Description |
|
|
911
|
+
|-------|----------|-------------|
|
|
912
|
+
| `NONE` | `none` | No notification sent |
|
|
913
|
+
| `AUDIO_ONLY` | `audio_only` | Audio notification after delay |
|
|
914
|
+
| `VISUAL_ONLY` | `visual_only` | Visual notification after delay |
|
|
915
|
+
| `AUDIO_AND_VISUAL` | `audio_and_visual` | Both audio and visual after delay |
|
|
916
|
+
|
|
917
|
+
### Phone Number / Extension Assignment
|
|
918
|
+
|
|
919
|
+
Call Pickup groups do not have their own phone numbers or extensions. They are groupings of agents -- members pick up ringing calls within the group using the feature access code `*98`.
|
|
920
|
+
|
|
921
|
+
### Member Management
|
|
922
|
+
|
|
923
|
+
- **Agents**: People, workspaces, and virtual lines. Set via the `agents` field (list of IDs on create/update).
|
|
924
|
+
- Use `available_agents()` to discover eligible agents at a location that are not yet assigned to another pickup group. The API excludes already-assigned agents from the results.
|
|
925
|
+
- A user can only belong to **one** call pickup group at a time. Attempting to add an already-assigned user returns error 4471: "User ... is already assigned to pickup group ...".
|
|
926
|
+
|
|
927
|
+
### Raw HTTP
|
|
928
|
+
|
|
929
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
930
|
+
|
|
931
|
+
```python
|
|
932
|
+
from wxc_sdk import WebexSimpleApi
|
|
933
|
+
api = WebexSimpleApi()
|
|
934
|
+
BASE = "https://webexapis.com/v1"
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
**List Call Pickups** (location-scoped):
|
|
938
|
+
|
|
939
|
+
```python
|
|
940
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callPickups",
|
|
941
|
+
params={"name": "Sales", "order": "ASC", "max": 1000})
|
|
942
|
+
items = result["callPickups"] # response key: "callPickups"
|
|
943
|
+
# Each item: {id, name}
|
|
944
|
+
```
|
|
945
|
+
|
|
946
|
+
**Get Call Pickup Details:**
|
|
947
|
+
|
|
948
|
+
```python
|
|
949
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callPickups/{pickup_id}")
|
|
950
|
+
# Returns: name, notificationType, notificationDelayTimerSeconds, agents[]
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
**Create Call Pickup** -- required: `name`:
|
|
954
|
+
|
|
955
|
+
```python
|
|
956
|
+
body = {
|
|
957
|
+
"name": "Sales Pickup",
|
|
958
|
+
"notificationType": "AUDIO_AND_VISUAL",
|
|
959
|
+
"notificationDelayTimerSeconds": 6,
|
|
960
|
+
"agents": [person_id] # Plain string array, NOT [{"id": person_id}]
|
|
961
|
+
}
|
|
962
|
+
# IMPORTANT: agents is an array of ID strings, not objects. [{"id": ...}] returns 400.
|
|
963
|
+
# Verified via stress test 2026-03-25.
|
|
964
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/callPickups", json=body)
|
|
965
|
+
pickup_id = result["id"]
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
**Update Call Pickup** (ID changes when name changes):
|
|
969
|
+
|
|
970
|
+
```python
|
|
971
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/callPickups/{pickup_id}",
|
|
972
|
+
json={"name": "New Name", "notificationType": "NONE"})
|
|
973
|
+
```
|
|
974
|
+
|
|
975
|
+
**Delete Call Pickup:**
|
|
976
|
+
|
|
977
|
+
```python
|
|
978
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/callPickups/{pickup_id}")
|
|
979
|
+
```
|
|
980
|
+
|
|
981
|
+
**Get Available Agents:**
|
|
982
|
+
|
|
983
|
+
```python
|
|
984
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/callPickups/availableUsers",
|
|
985
|
+
params={"name": "Jane", "max": 1000})
|
|
986
|
+
items = result["availableUsers"] # response key: "availableUsers"
|
|
987
|
+
```
|
|
988
|
+
|
|
989
|
+
### CLI Examples
|
|
990
|
+
|
|
991
|
+
```bash
|
|
992
|
+
# List call pickups at a location
|
|
993
|
+
wxcli call-pickup list --location-id <loc_id>
|
|
994
|
+
|
|
995
|
+
# Get details for a call pickup group
|
|
996
|
+
wxcli call-pickup show --location-id <loc_id> --call-pickup-id <pickup_id>
|
|
997
|
+
|
|
998
|
+
# Create a call pickup group
|
|
999
|
+
wxcli call-pickup create --location-id <loc_id> --name "Sales Pickup"
|
|
1000
|
+
|
|
1001
|
+
# Update a call pickup group
|
|
1002
|
+
wxcli call-pickup update --location-id <loc_id> --call-pickup-id <pickup_id> --name "New Name"
|
|
1003
|
+
|
|
1004
|
+
# Delete a call pickup group
|
|
1005
|
+
wxcli call-pickup delete --location-id <loc_id> --call-pickup-id <pickup_id>
|
|
1006
|
+
|
|
1007
|
+
# List available agents for call pickup
|
|
1008
|
+
wxcli call-pickup list-available-users --location-id <loc_id>
|
|
1009
|
+
```
|
|
1010
|
+
|
|
1011
|
+
---
|
|
1012
|
+
|
|
1013
|
+
## Voicemail Groups
|
|
1014
|
+
|
|
1015
|
+
### Overview
|
|
1016
|
+
|
|
1017
|
+
Voicemail Groups provide a **shared voicemail box** (and optional inbound fax box) that can be assigned to users or call routing features like auto attendants, call queues, or hunt groups. They are useful for team-level voicemail where multiple people need access to the same messages.
|
|
1018
|
+
|
|
1019
|
+
### SDK API Class
|
|
1020
|
+
|
|
1021
|
+
```python
|
|
1022
|
+
class VoicemailGroupsApi(ApiChild, base='telephony/config/voicemailGroups')
|
|
1023
|
+
```
|
|
1024
|
+
|
|
1025
|
+
### API Operations
|
|
1026
|
+
|
|
1027
|
+
#### List Voicemail Groups
|
|
1028
|
+
|
|
1029
|
+
```python
|
|
1030
|
+
def list(
|
|
1031
|
+
self,
|
|
1032
|
+
location_id: str = None,
|
|
1033
|
+
name: str = None,
|
|
1034
|
+
phone_number: str = None,
|
|
1035
|
+
org_id: str = None,
|
|
1036
|
+
**params
|
|
1037
|
+
) -> Generator[VoicemailGroup, None, None]
|
|
1038
|
+
```
|
|
1039
|
+
|
|
1040
|
+
- `name`: Search (contains) based on voicemail group name.
|
|
1041
|
+
- `phone_number`: Search (contains) based on number or extension.
|
|
1042
|
+
|
|
1043
|
+
#### Get Voicemail Group Details
|
|
1044
|
+
|
|
1045
|
+
```python
|
|
1046
|
+
def details(
|
|
1047
|
+
self,
|
|
1048
|
+
location_id: str,
|
|
1049
|
+
voicemail_group_id: str,
|
|
1050
|
+
org_id: str = None
|
|
1051
|
+
) -> VoicemailGroupDetail
|
|
1052
|
+
```
|
|
1053
|
+
|
|
1054
|
+
#### Create Voicemail Group
|
|
1055
|
+
|
|
1056
|
+
```python
|
|
1057
|
+
def create(
|
|
1058
|
+
self,
|
|
1059
|
+
location_id: str,
|
|
1060
|
+
settings: VoicemailGroupDetail,
|
|
1061
|
+
org_id: str = None
|
|
1062
|
+
) -> str # returns new voicemail group ID
|
|
1063
|
+
```
|
|
1064
|
+
|
|
1065
|
+
Convenience factory with sensible defaults (internal storage, all notifications disabled):
|
|
1066
|
+
|
|
1067
|
+
```python
|
|
1068
|
+
settings = VoicemailGroupDetail.create(
|
|
1069
|
+
name='Support VM',
|
|
1070
|
+
extension='8200',
|
|
1071
|
+
first_name='Support',
|
|
1072
|
+
last_name='Team',
|
|
1073
|
+
passcode=740384,
|
|
1074
|
+
language_code='en_us',
|
|
1075
|
+
phone_number='+14155551234' # optional
|
|
1076
|
+
)
|
|
1077
|
+
vmg_id = api.telephony.voicemail_groups.create(
|
|
1078
|
+
location_id=loc_id, settings=settings
|
|
1079
|
+
)
|
|
1080
|
+
```
|
|
1081
|
+
|
|
1082
|
+
#### Update Voicemail Group
|
|
1083
|
+
|
|
1084
|
+
```python
|
|
1085
|
+
def update(
|
|
1086
|
+
self,
|
|
1087
|
+
location_id: str,
|
|
1088
|
+
voicemail_group_id: str,
|
|
1089
|
+
settings: VoicemailGroupDetail,
|
|
1090
|
+
org_id: str = None
|
|
1091
|
+
) -> None
|
|
1092
|
+
```
|
|
1093
|
+
|
|
1094
|
+
#### Delete Voicemail Group
|
|
1095
|
+
|
|
1096
|
+
```python
|
|
1097
|
+
def delete(
|
|
1098
|
+
self,
|
|
1099
|
+
location_id: str,
|
|
1100
|
+
voicemail_group_id: str,
|
|
1101
|
+
org_id: str = None
|
|
1102
|
+
) -> None
|
|
1103
|
+
```
|
|
1104
|
+
|
|
1105
|
+
#### Get Available Phone Numbers
|
|
1106
|
+
|
|
1107
|
+
```python
|
|
1108
|
+
def available_phone_numbers(
|
|
1109
|
+
self,
|
|
1110
|
+
location_id: str,
|
|
1111
|
+
phone_number: List[str] = None,
|
|
1112
|
+
org_id: str = None,
|
|
1113
|
+
**params
|
|
1114
|
+
) -> Generator[AvailableNumber, None, None]
|
|
1115
|
+
```
|
|
1116
|
+
|
|
1117
|
+
#### Get Fax Message Available Phone Numbers
|
|
1118
|
+
|
|
1119
|
+
```python
|
|
1120
|
+
def fax_message_available_phone_numbers(
|
|
1121
|
+
self,
|
|
1122
|
+
location_id: str,
|
|
1123
|
+
phone_number: List[str] = None,
|
|
1124
|
+
org_id: str = None,
|
|
1125
|
+
**params
|
|
1126
|
+
) -> Generator[AvailableNumber, None, None]
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
Lists numbers available to be assigned as the voicemail group's fax message phone number.
|
|
1130
|
+
|
|
1131
|
+
### Key Data Models
|
|
1132
|
+
|
|
1133
|
+
#### `VoicemailGroup` (List Model)
|
|
1134
|
+
|
|
1135
|
+
| Field | Type | Notes |
|
|
1136
|
+
|-------|------|-------|
|
|
1137
|
+
| `group_id` (alias: `id`) | `str` | Unique identifier |
|
|
1138
|
+
| `name` | `str` | Group name |
|
|
1139
|
+
| `location_name` | `str` | Location name |
|
|
1140
|
+
| `location_id` | `str` | Location ID |
|
|
1141
|
+
| `extension` | `str` | Extension number |
|
|
1142
|
+
| `phone_number` | `str` | Phone number |
|
|
1143
|
+
| `routing_prefix` | `str` | Location routing prefix |
|
|
1144
|
+
| `esn` | `str` | Routing prefix + extension |
|
|
1145
|
+
| `enabled` | `bool` | Whether incoming calls are sent to voicemail |
|
|
1146
|
+
| `toll_free_number` | `bool` | Read-only |
|
|
1147
|
+
|
|
1148
|
+
#### `VoicemailGroupDetail` (Detail/Create/Update Model)
|
|
1149
|
+
|
|
1150
|
+
| Field | Type | Required for Create | Notes |
|
|
1151
|
+
|-------|------|-------------------|-------|
|
|
1152
|
+
| `group_id` (alias: `id`) | `str` | -- | Read-only |
|
|
1153
|
+
| `name` | `str` | **Yes** | Group name |
|
|
1154
|
+
| `phone_number` | `str` | No | Voicemail group phone number |
|
|
1155
|
+
| `extension` | `str` | **Yes** | Extension number |
|
|
1156
|
+
| `first_name` | `str` | **Yes** | **Deprecated** -- use `direct_line_caller_id_name` |
|
|
1157
|
+
| `last_name` | `str` | **Yes** | **Deprecated** -- use `direct_line_caller_id_name` |
|
|
1158
|
+
| `passcode` | `int` | **Yes** | Access passcode |
|
|
1159
|
+
| `enabled` | `bool` | No | For update only |
|
|
1160
|
+
| `language_code` | `str` | No | Default `en_us` in factory |
|
|
1161
|
+
| `greeting` | `Greeting` | No | Greeting type enum |
|
|
1162
|
+
| `greeting_uploaded` | `bool` | -- | Read-only; `True` if custom greeting uploaded |
|
|
1163
|
+
| `greeting_description` | `str` | No | Description for custom greeting |
|
|
1164
|
+
| `message_storage` | `VoicemailMessageStorage` | **Yes** (set by factory) | Storage type config |
|
|
1165
|
+
| `notifications` | `VoicemailNotifications` | **Yes** (set by factory) | Notification settings |
|
|
1166
|
+
| `fax_message` | `VoicemailFax` | **Yes** (set by factory) | Fax receive settings |
|
|
1167
|
+
| `transfer_to_number` | `VoicemailTransferToNumber` | **Yes** (set by factory) | Transfer settings |
|
|
1168
|
+
| `email_copy_of_message` | `VoicemailCopyOfMessage` | **Yes** (set by factory) | Email copy settings |
|
|
1169
|
+
| `voice_message_forwarding_enabled` | `bool` | No | Enable/disable voice message forwarding |
|
|
1170
|
+
| `time_zone` | `str` | No | Undocumented field -- present in API response and wxc_sdk model (`# TODO: undocumented`) but absent from OpenAPI spec `GetLocationVoicemailGroupObject` schema. |
|
|
1171
|
+
| `direct_line_caller_id_name` | `DirectLineCallerIdName` | No | Replaces deprecated first/last name |
|
|
1172
|
+
| `dial_by_name` | `str` | No | Name for dial-by-name directory |
|
|
1173
|
+
|
|
1174
|
+
#### `VoicemailMessageStorage`
|
|
1175
|
+
|
|
1176
|
+
| Field | Type | Notes |
|
|
1177
|
+
|-------|------|-------|
|
|
1178
|
+
| `storage_type` | `StorageType` | `INTERNAL` (Webex-hosted) or `EXTERNAL` (external server) |
|
|
1179
|
+
| `external_email` | `str` | Email address for external storage delivery |
|
|
1180
|
+
|
|
1181
|
+
#### `VoicemailNotifications`
|
|
1182
|
+
|
|
1183
|
+
| Field | Type | Notes |
|
|
1184
|
+
|-------|------|-------|
|
|
1185
|
+
| `enabled` | `bool` | Whether notifications are sent |
|
|
1186
|
+
| `destination` | `str` | Email address or phone number for notifications |
|
|
1187
|
+
|
|
1188
|
+
#### `VoicemailFax`
|
|
1189
|
+
|
|
1190
|
+
| Field | Type | Notes |
|
|
1191
|
+
|-------|------|-------|
|
|
1192
|
+
| `enabled` | `bool` | Whether fax reception is enabled |
|
|
1193
|
+
| `phone_number` | `str` | Dedicated fax phone number |
|
|
1194
|
+
|
|
1195
|
+
#### `VoicemailTransferToNumber`
|
|
1196
|
+
|
|
1197
|
+
| Field | Type | Notes |
|
|
1198
|
+
|-------|------|-------|
|
|
1199
|
+
| `enabled` | `bool` | Whether transfer-to-number is enabled |
|
|
1200
|
+
| `destination` | `str` | Number to transfer to when the caller presses 0 |
|
|
1201
|
+
|
|
1202
|
+
#### `VoicemailCopyOfMessage`
|
|
1203
|
+
|
|
1204
|
+
| Field | Type | Notes |
|
|
1205
|
+
|-------|------|-------|
|
|
1206
|
+
| `enabled` | `bool` | Whether email copies of voicemail are sent |
|
|
1207
|
+
| `email_id` | `str` | Email address to receive message copies |
|
|
1208
|
+
|
|
1209
|
+
The `VoicemailGroupDetail.create()` factory sets these defaults:
|
|
1210
|
+
- `message_storage`: `StorageType.internal`
|
|
1211
|
+
- `notifications`: disabled
|
|
1212
|
+
- `fax_message`: disabled
|
|
1213
|
+
- `transfer_to_number`: disabled
|
|
1214
|
+
- `email_copy_of_message`: disabled
|
|
1215
|
+
|
|
1216
|
+
### Phone Number / Extension Assignment
|
|
1217
|
+
|
|
1218
|
+
- `extension` is **required** on create.
|
|
1219
|
+
- `phone_number` is optional.
|
|
1220
|
+
- Use `available_phone_numbers()` and `fax_message_available_phone_numbers()` to find unassigned numbers at a location.
|
|
1221
|
+
|
|
1222
|
+
### Member Management
|
|
1223
|
+
|
|
1224
|
+
Voicemail Groups do not have explicit member lists. They are shared voicemail boxes that are **assigned to** other features (auto attendants, call queues, hunt groups) or users through those features' overflow/no-answer settings.
|
|
1225
|
+
|
|
1226
|
+
### Raw HTTP
|
|
1227
|
+
|
|
1228
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
1229
|
+
|
|
1230
|
+
The Voicemail Groups CLI uses SDK methods (not raw HTTP) for most operations. The SDK base is `telephony/config/voicemailGroups`. The underlying API URLs are:
|
|
1231
|
+
|
|
1232
|
+
```python
|
|
1233
|
+
from wxc_sdk import WebexSimpleApi
|
|
1234
|
+
api = WebexSimpleApi()
|
|
1235
|
+
BASE = "https://webexapis.com/v1"
|
|
1236
|
+
```
|
|
1237
|
+
|
|
1238
|
+
**List Voicemail Groups** (org-wide):
|
|
1239
|
+
|
|
1240
|
+
```python
|
|
1241
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/voicemailGroups",
|
|
1242
|
+
params={"locationId": loc_id, "name": "Support", "max": 1000})
|
|
1243
|
+
items = result["voicemailGroups"] # response key: "voicemailGroups"
|
|
1244
|
+
# Each item: {id, name, locationName, locationId, extension, phoneNumber, routingPrefix, esn, enabled, tollFreeNumber}
|
|
1245
|
+
```
|
|
1246
|
+
|
|
1247
|
+
**Get Voicemail Group Details:**
|
|
1248
|
+
|
|
1249
|
+
```python
|
|
1250
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vg_id}")
|
|
1251
|
+
# Returns: name, extension, passcode, languageCode, messageStorage, notifications, faxMessage, etc.
|
|
1252
|
+
```
|
|
1253
|
+
|
|
1254
|
+
**Create Voicemail Group** -- requires 7+ fields (name, extension, passcode, languageCode, messageStorage, notifications, faxMessage, transferToNumber, emailCopyOfMessage):
|
|
1255
|
+
|
|
1256
|
+
```python
|
|
1257
|
+
body = {
|
|
1258
|
+
"name": "Support VM",
|
|
1259
|
+
"extension": "8200",
|
|
1260
|
+
"passcode": "740384", # 6+ digits, no sequential/repeating patterns
|
|
1261
|
+
"languageCode": "en_us",
|
|
1262
|
+
"messageStorage": {"storageType": "INTERNAL"},
|
|
1263
|
+
"notifications": {"enabled": False},
|
|
1264
|
+
"faxMessage": {"enabled": False},
|
|
1265
|
+
"transferToNumber": {"enabled": False},
|
|
1266
|
+
"emailCopyOfMessage": {"enabled": False}
|
|
1267
|
+
}
|
|
1268
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups", json=body)
|
|
1269
|
+
vg_id = result["id"]
|
|
1270
|
+
```
|
|
1271
|
+
|
|
1272
|
+
**Gotcha**: The wxc_sdk `VoicemailGroupDetail.for_create()` method has a bug -- missing `by_alias=True`, which sends snake_case keys instead of camelCase. Workaround: `model_dump(mode='json', by_alias=True, exclude_unset=True)`.
|
|
1273
|
+
|
|
1274
|
+
**Update Voicemail Group:**
|
|
1275
|
+
|
|
1276
|
+
```python
|
|
1277
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vg_id}",
|
|
1278
|
+
json={"name": "New Name", "enabled": True})
|
|
1279
|
+
```
|
|
1280
|
+
|
|
1281
|
+
**Delete Voicemail Group:**
|
|
1282
|
+
|
|
1283
|
+
```python
|
|
1284
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/{vg_id}")
|
|
1285
|
+
```
|
|
1286
|
+
|
|
1287
|
+
**Get Available Phone Numbers:**
|
|
1288
|
+
|
|
1289
|
+
```python
|
|
1290
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/availablePhoneNumbers",
|
|
1291
|
+
params={"max": 1000})
|
|
1292
|
+
items = result["phoneNumbers"]
|
|
1293
|
+
```
|
|
1294
|
+
|
|
1295
|
+
**Get Fax Message Available Phone Numbers:**
|
|
1296
|
+
|
|
1297
|
+
```python
|
|
1298
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/voicemailGroups/faxMessage/availablePhoneNumbers",
|
|
1299
|
+
params={"max": 1000})
|
|
1300
|
+
items = result["phoneNumbers"]
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
### CLI Examples
|
|
1304
|
+
|
|
1305
|
+
Voicemail Group commands are under the `location-voicemail` command group.
|
|
1306
|
+
|
|
1307
|
+
```bash
|
|
1308
|
+
# List voicemail groups (org-wide or filtered by location)
|
|
1309
|
+
wxcli location-voicemail list --location-id <loc_id>
|
|
1310
|
+
|
|
1311
|
+
# Get details for a voicemail group
|
|
1312
|
+
wxcli location-voicemail show-voicemail-groups --location-id <loc_id> --voicemail-group-id <vg_id>
|
|
1313
|
+
|
|
1314
|
+
# Create a voicemail group
|
|
1315
|
+
wxcli location-voicemail create --location-id <loc_id> --name "Support VM" --extension "8200" \
|
|
1316
|
+
--json-body '{"passcode": "740384", "languageCode": "en_us", "messageStorage": {"storageType": "INTERNAL"}, "notifications": {"enabled": false}, "faxMessage": {"enabled": false}, "transferToNumber": {"enabled": false}, "emailCopyOfMessage": {"enabled": false}}'
|
|
1317
|
+
|
|
1318
|
+
# Update a voicemail group
|
|
1319
|
+
wxcli location-voicemail update-voicemail-groups --location-id <loc_id> --voicemail-group-id <vg_id> \
|
|
1320
|
+
--name "New Name"
|
|
1321
|
+
|
|
1322
|
+
# Delete a voicemail group
|
|
1323
|
+
wxcli location-voicemail delete --location-id <loc_id> --voicemail-group-id <vg_id>
|
|
1324
|
+
|
|
1325
|
+
# List available phone numbers for voicemail group assignment
|
|
1326
|
+
wxcli location-voicemail list-available-numbers-voicemail-groups --location-id <loc_id>
|
|
1327
|
+
|
|
1328
|
+
# List available phone numbers for fax message
|
|
1329
|
+
wxcli location-voicemail list-available-numbers-fax-message --location-id <loc_id>
|
|
1330
|
+
```
|
|
1331
|
+
|
|
1332
|
+
---
|
|
1333
|
+
|
|
1334
|
+
## Customer Assist (CX Essentials)
|
|
1335
|
+
|
|
1336
|
+
> **Not to be confused with Webex Contact Center (WxCC).** Customer Assist (formerly CX Essentials) is a Webex Calling add-on for basic queue supervision and agent experience. Webex Contact Center is a separate product with its own developer portal at `developer.webex-cx.com`, separate APIs, and separate licensing. This playbook covers Customer Assist only.
|
|
1337
|
+
|
|
1338
|
+
### Overview
|
|
1339
|
+
|
|
1340
|
+
Webex **Customer Assist** (formerly Customer Experience Essentials / CX Essentials) provides enhanced queue capabilities beyond the Customer Experience Basic suite. It adds features such as:
|
|
1341
|
+
|
|
1342
|
+
- **Screen Pop**: Pop a URL (CRM, ticketing system) when an agent receives a queued call
|
|
1343
|
+
- **Queue Call Recording**: Hosted call recording for quality assurance, compliance, and training
|
|
1344
|
+
- **Wrap-Up Reasons**: Post-call categorization codes that agents select after ending a call
|
|
1345
|
+
- **Customer Assist Agent Licensing**: Ability to query agents with Customer Assist licenses
|
|
1346
|
+
|
|
1347
|
+
These APIs are distinct from Customer Experience Basic and require Customer Assist licensing.
|
|
1348
|
+
|
|
1349
|
+
### SDK API Class
|
|
1350
|
+
|
|
1351
|
+
```python
|
|
1352
|
+
@dataclass(init=False, repr=False)
|
|
1353
|
+
class CustomerExperienceEssentialsApi(ApiChild, base='telephony/config')
|
|
1354
|
+
```
|
|
1355
|
+
|
|
1356
|
+
Sub-APIs:
|
|
1357
|
+
|
|
1358
|
+
```python
|
|
1359
|
+
api.telephony.cx_essentials.callqueue_recording # QueueCallRecordingSettingsApi
|
|
1360
|
+
api.telephony.cx_essentials.wrapup_reasons # WrapupReasonApi
|
|
1361
|
+
```
|
|
1362
|
+
|
|
1363
|
+
### Screen Pop Configuration
|
|
1364
|
+
|
|
1365
|
+
Screen pop lets agents view customer-related info in a pop-up window when receiving a call from a queue.
|
|
1366
|
+
|
|
1367
|
+
#### Get Screen Pop Configuration
|
|
1368
|
+
|
|
1369
|
+
```python
|
|
1370
|
+
def get_screen_pop_configuration(
|
|
1371
|
+
self,
|
|
1372
|
+
location_id: str = None,
|
|
1373
|
+
queue_id: str = None,
|
|
1374
|
+
org_id: str = None
|
|
1375
|
+
) -> ScreenPopConfiguration
|
|
1376
|
+
```
|
|
1377
|
+
|
|
1378
|
+
#### Modify Screen Pop Configuration
|
|
1379
|
+
|
|
1380
|
+
```python
|
|
1381
|
+
def modify_screen_pop_configuration(
|
|
1382
|
+
self,
|
|
1383
|
+
location_id: str,
|
|
1384
|
+
queue_id: str,
|
|
1385
|
+
settings: ScreenPopConfiguration,
|
|
1386
|
+
org_id: str = None
|
|
1387
|
+
) -> None
|
|
1388
|
+
```
|
|
1389
|
+
|
|
1390
|
+
#### `ScreenPopConfiguration` Model
|
|
1391
|
+
|
|
1392
|
+
| Field | Type | Notes |
|
|
1393
|
+
|-------|------|-------|
|
|
1394
|
+
| `enabled` | `bool` | Enable/disable screen pop |
|
|
1395
|
+
| `screen_pop_url` | `str` | URL to pop (CRM, ticketing, etc.) |
|
|
1396
|
+
| `desktop_label` | `str` | Label for the screen pop config |
|
|
1397
|
+
| `query_params` | `dict[str, Any]` | Query parameters appended to the screen pop URL |
|
|
1398
|
+
|
|
1399
|
+
### Available Agents
|
|
1400
|
+
|
|
1401
|
+
#### List Customer Assist Available Agents
|
|
1402
|
+
|
|
1403
|
+
```python
|
|
1404
|
+
def available_agents(
|
|
1405
|
+
self,
|
|
1406
|
+
location_id: str,
|
|
1407
|
+
has_cx_essentials: bool = None,
|
|
1408
|
+
org_id: str = None
|
|
1409
|
+
) -> Generator[AvailableAgent, None, None]
|
|
1410
|
+
```
|
|
1411
|
+
|
|
1412
|
+
- `has_cx_essentials=True`: Returns only agents with Customer Assist (formerly CX Essentials) license.
|
|
1413
|
+
- `has_cx_essentials=False`: Returns only agents with CX Basic license.
|
|
1414
|
+
- Omit for all agents.
|
|
1415
|
+
|
|
1416
|
+
### Queue Call Recording
|
|
1417
|
+
|
|
1418
|
+
Hosted call recording for queues. Records calls placed and received on the platform for replay and archival.
|
|
1419
|
+
|
|
1420
|
+
#### Read Queue Call Recording Settings
|
|
1421
|
+
|
|
1422
|
+
```python
|
|
1423
|
+
def read(
|
|
1424
|
+
self,
|
|
1425
|
+
location_id: str,
|
|
1426
|
+
queue_id: str,
|
|
1427
|
+
org_id: str = None
|
|
1428
|
+
) -> CallRecordingSetting
|
|
1429
|
+
```
|
|
1430
|
+
|
|
1431
|
+
**Scope**: `spark-admin:people_read`
|
|
1432
|
+
|
|
1433
|
+
#### Configure Queue Call Recording Settings
|
|
1434
|
+
|
|
1435
|
+
```python
|
|
1436
|
+
def configure(
|
|
1437
|
+
self,
|
|
1438
|
+
location_id: str,
|
|
1439
|
+
queue_id: str,
|
|
1440
|
+
recording: CallRecordingSetting,
|
|
1441
|
+
org_id: str = None
|
|
1442
|
+
) -> None
|
|
1443
|
+
```
|
|
1444
|
+
|
|
1445
|
+
**Scope**: `spark-admin:people_write`
|
|
1446
|
+
|
|
1447
|
+
**Note**: A person with a Webex Calling Standard license is eligible for call recording only when the recording vendor is Webex.
|
|
1448
|
+
|
|
1449
|
+
#### Raw HTTP
|
|
1450
|
+
|
|
1451
|
+
```
|
|
1452
|
+
GET /v1/telephony/config/locations/{locationId}/queues/{queueId}/cxEssentials/callRecordings
|
|
1453
|
+
PUT /v1/telephony/config/locations/{locationId}/queues/{queueId}/cxEssentials/callRecordings
|
|
1454
|
+
```
|
|
1455
|
+
|
|
1456
|
+
GET response / PUT body fields: `enabled` (bool), `record` (str: Always/Never/OnDemand), `notification` (object: `{enabled, type}`), `repeat` (object: `{enabled, interval}`), `startStopAnnouncement` (object: `{internalCallsEnabled, pstnCallsEnabled}`), `serviceProvider` (str), `externalGroup` (str), `externalIdentifier` (str).
|
|
1457
|
+
|
|
1458
|
+
Scope: `spark-admin:people_read` (GET), `spark-admin:people_write` (PUT).
|
|
1459
|
+
|
|
1460
|
+
### Wrap-Up Reasons
|
|
1461
|
+
|
|
1462
|
+
Wrap-up reasons let agents categorize the outcome of a call after it ends. Admins configure reasons and assign them to queues. A configurable timer (default 60 seconds) dictates how long agents have to select a reason post-call.
|
|
1463
|
+
|
|
1464
|
+
#### List Wrap-Up Reasons (Org-Level)
|
|
1465
|
+
|
|
1466
|
+
```python
|
|
1467
|
+
def list(self) -> List[WrapUpReason]
|
|
1468
|
+
```
|
|
1469
|
+
|
|
1470
|
+
Returns all wrap-up reasons configured for the organization. No parameters needed.
|
|
1471
|
+
|
|
1472
|
+
#### Get Wrap-Up Reason Details
|
|
1473
|
+
|
|
1474
|
+
```python
|
|
1475
|
+
def details(
|
|
1476
|
+
self,
|
|
1477
|
+
wrapup_reason_id: str
|
|
1478
|
+
) -> WrapUpReasonDetails
|
|
1479
|
+
```
|
|
1480
|
+
|
|
1481
|
+
Returns the reason details including assigned queues.
|
|
1482
|
+
|
|
1483
|
+
#### Create Wrap-Up Reason
|
|
1484
|
+
|
|
1485
|
+
```python
|
|
1486
|
+
def create(
|
|
1487
|
+
self,
|
|
1488
|
+
name: str,
|
|
1489
|
+
description: str = None,
|
|
1490
|
+
queues: List[str] = None,
|
|
1491
|
+
assign_all_queues_enabled: bool = None
|
|
1492
|
+
) -> str # returns wrap-up reason ID
|
|
1493
|
+
```
|
|
1494
|
+
|
|
1495
|
+
- `queues`: List of queue IDs to assign.
|
|
1496
|
+
- `assign_all_queues_enabled`: Assign to all queues at once.
|
|
1497
|
+
|
|
1498
|
+
#### Update Wrap-Up Reason
|
|
1499
|
+
|
|
1500
|
+
```python
|
|
1501
|
+
def update(
|
|
1502
|
+
self,
|
|
1503
|
+
wrapup_reason_id: str,
|
|
1504
|
+
name: str = None,
|
|
1505
|
+
description: str = None,
|
|
1506
|
+
queues_to_assign: List[str] = None,
|
|
1507
|
+
queues_to_unassign: List[str] = None,
|
|
1508
|
+
assign_all_queues_enabled: bool = None,
|
|
1509
|
+
unassign_all_queues_enabled: bool = None
|
|
1510
|
+
) -> None
|
|
1511
|
+
```
|
|
1512
|
+
|
|
1513
|
+
Queue assignment is **incremental** -- you can assign and unassign specific queues without replacing the full list.
|
|
1514
|
+
|
|
1515
|
+
#### Delete Wrap-Up Reason
|
|
1516
|
+
|
|
1517
|
+
```python
|
|
1518
|
+
def delete(
|
|
1519
|
+
self,
|
|
1520
|
+
wrapup_reason_id: str
|
|
1521
|
+
) -> None
|
|
1522
|
+
```
|
|
1523
|
+
|
|
1524
|
+
#### Validate Wrap-Up Reason Name
|
|
1525
|
+
|
|
1526
|
+
```python
|
|
1527
|
+
def validate(
|
|
1528
|
+
self,
|
|
1529
|
+
name: str
|
|
1530
|
+
) -> None
|
|
1531
|
+
```
|
|
1532
|
+
|
|
1533
|
+
Check if a wrap-up reason name is valid (not already taken). Raises an error on conflict.
|
|
1534
|
+
|
|
1535
|
+
#### Read Queue Wrap-Up Settings
|
|
1536
|
+
|
|
1537
|
+
```python
|
|
1538
|
+
def read_queue_settings(
|
|
1539
|
+
self,
|
|
1540
|
+
location_id: str,
|
|
1541
|
+
queue_id: str
|
|
1542
|
+
) -> QueueWrapupReasonSettings
|
|
1543
|
+
```
|
|
1544
|
+
|
|
1545
|
+
Returns wrap-up configuration for a specific queue: timer settings and assigned reasons.
|
|
1546
|
+
|
|
1547
|
+
#### Update Queue Wrap-Up Settings
|
|
1548
|
+
|
|
1549
|
+
```python
|
|
1550
|
+
def update_queue_settings(
|
|
1551
|
+
self,
|
|
1552
|
+
location_id: str,
|
|
1553
|
+
queue_id: str,
|
|
1554
|
+
wrapup_reasons: list[str] = None,
|
|
1555
|
+
default_wrapup_reason_id: str = None,
|
|
1556
|
+
wrapup_timer_enabled: bool = None,
|
|
1557
|
+
wrapup_timer: int = None
|
|
1558
|
+
) -> None
|
|
1559
|
+
```
|
|
1560
|
+
|
|
1561
|
+
- `default_wrapup_reason_id`: Set as `''` (empty string) to clear the default.
|
|
1562
|
+
- `wrapup_timer`: Timer value in seconds (default is 60).
|
|
1563
|
+
|
|
1564
|
+
#### Get Available Queues for Wrap-Up Reason
|
|
1565
|
+
|
|
1566
|
+
```python
|
|
1567
|
+
def available_queues(
|
|
1568
|
+
self,
|
|
1569
|
+
wrapup_reason_id: str
|
|
1570
|
+
) -> List[AvailableQueue]
|
|
1571
|
+
```
|
|
1572
|
+
|
|
1573
|
+
Returns queues that are not yet assigned to this wrap-up reason and can be added.
|
|
1574
|
+
|
|
1575
|
+
### Customer Assist Data Models
|
|
1576
|
+
|
|
1577
|
+
#### `WrapUpReason` (List Model)
|
|
1578
|
+
|
|
1579
|
+
| Field | Type | Notes |
|
|
1580
|
+
|-------|------|-------|
|
|
1581
|
+
| `id` | `str` | Unique identifier |
|
|
1582
|
+
| `name` | `str` | Reason name |
|
|
1583
|
+
| `description` | `str` | Reason description |
|
|
1584
|
+
| `number_of_queues_assigned` | `int` | Count of assigned queues |
|
|
1585
|
+
|
|
1586
|
+
#### `WrapUpReasonDetails` (Detail Model)
|
|
1587
|
+
|
|
1588
|
+
| Field | Type | Notes |
|
|
1589
|
+
|-------|------|-------|
|
|
1590
|
+
| `name` | `str` | Reason name |
|
|
1591
|
+
| `description` | `str` | Reason description |
|
|
1592
|
+
| `default_wrapup_queues_count` | `int` | Number of queues where this is the default |
|
|
1593
|
+
| `queues` | `list[WrapupReasonQueue]` | Assigned queues with full details |
|
|
1594
|
+
|
|
1595
|
+
#### `WrapupReasonQueue`
|
|
1596
|
+
|
|
1597
|
+
| Field | Type | Notes |
|
|
1598
|
+
|-------|------|-------|
|
|
1599
|
+
| `id` | `str` | Queue ID |
|
|
1600
|
+
| `name` | `str` | Queue name |
|
|
1601
|
+
| `location_name` | `str` | Location name |
|
|
1602
|
+
| `location_id` | `str` | Location ID |
|
|
1603
|
+
| `phone_number` | `str` | Queue phone number |
|
|
1604
|
+
| `extension` | `int` | Queue extension |
|
|
1605
|
+
| `default_wrapup_enabled` | `bool` | Whether this reason is the default for the queue |
|
|
1606
|
+
|
|
1607
|
+
#### `QueueWrapupReasonSettings`
|
|
1608
|
+
|
|
1609
|
+
| Field | Type | Notes |
|
|
1610
|
+
|-------|------|-------|
|
|
1611
|
+
| `wrapup_timer_enabled` | `bool` | Whether the wrap-up timer is active |
|
|
1612
|
+
| `wrapup_timer` | `int` | Timer value in seconds |
|
|
1613
|
+
| `wrapup_reasons` | `list[QueueSettingsReason]` | Reasons assigned to this queue |
|
|
1614
|
+
|
|
1615
|
+
#### `QueueSettingsReason`
|
|
1616
|
+
|
|
1617
|
+
| Field | Type | Notes |
|
|
1618
|
+
|-------|------|-------|
|
|
1619
|
+
| `id` | `str` | Wrap-up reason ID |
|
|
1620
|
+
| `name` | `str` | Reason name |
|
|
1621
|
+
| `description` | `str` | Reason description |
|
|
1622
|
+
| `default_enabled` | `bool` | Whether this reason is the default for the queue |
|
|
1623
|
+
|
|
1624
|
+
#### `AvailableQueue`
|
|
1625
|
+
|
|
1626
|
+
| Field | Type | Notes |
|
|
1627
|
+
|-------|------|-------|
|
|
1628
|
+
| `id` | `str` | Queue ID |
|
|
1629
|
+
| `name` | `str` | Queue name |
|
|
1630
|
+
| `location_name` | `str` | Location name |
|
|
1631
|
+
| `location_id` | `str` | Location ID |
|
|
1632
|
+
| `phone_number` | `str` | Queue phone number |
|
|
1633
|
+
| `extension` | `int` | Queue extension |
|
|
1634
|
+
|
|
1635
|
+
### Raw HTTP (Customer Assist)
|
|
1636
|
+
|
|
1637
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
1638
|
+
|
|
1639
|
+
Customer Assist (formerly CX Essentials) APIs operate on call queues. The base URL pattern is `telephony/config/cxEssentials/...` or queue-scoped paths.
|
|
1640
|
+
|
|
1641
|
+
```python
|
|
1642
|
+
from wxc_sdk import WebexSimpleApi
|
|
1643
|
+
api = WebexSimpleApi()
|
|
1644
|
+
BASE = "https://webexapis.com/v1"
|
|
1645
|
+
```
|
|
1646
|
+
|
|
1647
|
+
**Note**: Customer Assist operations require Customer Assist licensing. Screen pop, queue recording, and wrap-up reasons are all per-queue settings -- call queues must exist first.
|
|
1648
|
+
|
|
1649
|
+
### CLI Examples
|
|
1650
|
+
|
|
1651
|
+
```bash
|
|
1652
|
+
# List all wrap-up reasons (org-level)
|
|
1653
|
+
wxcli cx-essentials list
|
|
1654
|
+
|
|
1655
|
+
# Get details for a wrap-up reason
|
|
1656
|
+
wxcli cx-essentials show REASON_ID -o json
|
|
1657
|
+
|
|
1658
|
+
# Create a wrap-up reason
|
|
1659
|
+
wxcli cx-essentials create --name "Customer Inquiry"
|
|
1660
|
+
|
|
1661
|
+
# Update a wrap-up reason
|
|
1662
|
+
wxcli cx-essentials update REASON_ID --name "Updated Reason"
|
|
1663
|
+
|
|
1664
|
+
# Delete a wrap-up reason
|
|
1665
|
+
wxcli cx-essentials delete REASON_ID --force
|
|
1666
|
+
|
|
1667
|
+
# Validate a wrap-up reason name
|
|
1668
|
+
wxcli cx-essentials validate-wrap-up --name "New Reason Name"
|
|
1669
|
+
|
|
1670
|
+
# List available queues for a wrap-up reason
|
|
1671
|
+
wxcli cx-essentials list-available-queues REASON_ID
|
|
1672
|
+
|
|
1673
|
+
# Get wrap-up reason settings for a queue
|
|
1674
|
+
wxcli cx-essentials list-settings LOCATION_ID QUEUE_ID -o json
|
|
1675
|
+
|
|
1676
|
+
# Update wrap-up reason settings for a queue
|
|
1677
|
+
wxcli cx-essentials update-settings LOCATION_ID QUEUE_ID \
|
|
1678
|
+
--json-body '{"wrapupTimerEnabled": true, "wrapupTimer": 60}'
|
|
1679
|
+
|
|
1680
|
+
# Get screen pop configuration for a queue
|
|
1681
|
+
wxcli cx-essentials show-screen-pop LOCATION_ID QUEUE_ID -o json
|
|
1682
|
+
|
|
1683
|
+
# Update screen pop configuration for a queue
|
|
1684
|
+
wxcli cx-essentials update-screen-pop LOCATION_ID QUEUE_ID \
|
|
1685
|
+
--json-body '{"enabled": true, "screenPopUrl": "https://crm.example.com/pop"}'
|
|
1686
|
+
|
|
1687
|
+
# List available agents (optionally filter by Customer Assist license)
|
|
1688
|
+
wxcli cx-essentials list-available-agents LOCATION_ID
|
|
1689
|
+
|
|
1690
|
+
# Get queue call recording settings
|
|
1691
|
+
wxcli cx-essentials show-queue-recording LOCATION_ID QUEUE_ID -o json
|
|
1692
|
+
|
|
1693
|
+
# Update queue call recording settings
|
|
1694
|
+
wxcli cx-essentials update-queue-recording LOCATION_ID QUEUE_ID \
|
|
1695
|
+
--enabled --record Always
|
|
1696
|
+
|
|
1697
|
+
# --- Queue Discovery & Creation ---
|
|
1698
|
+
|
|
1699
|
+
# List Customer Assist queues (hidden from default call-queue list!)
|
|
1700
|
+
wxcli call-queue list --has-cx-essentials true -o json
|
|
1701
|
+
|
|
1702
|
+
# Create a Customer Assist queue (requires callPolicies via --json-body)
|
|
1703
|
+
wxcli call-queue create LOCATION_ID --name "Queue Name" --has-cx-essentials true \
|
|
1704
|
+
--json-body '{"name":"Queue Name","extension":"XXXX","callPolicies":{"policy":"SIMULTANEOUS"}}'
|
|
1705
|
+
|
|
1706
|
+
# --- Supervisor Cleanup ---
|
|
1707
|
+
|
|
1708
|
+
# To remove a supervisor, remove all agents via update (not delete endpoint)
|
|
1709
|
+
wxcli call-queue update-supervisors SUPERVISOR_ID --has-cx-essentials true \
|
|
1710
|
+
--json-body '{"agents":[{"id":"AGENT_ID","action":"DELETE"}]}'
|
|
1711
|
+
# When last agent is removed, supervisor is auto-deleted
|
|
1712
|
+
```
|
|
1713
|
+
|
|
1714
|
+
> **GOTCHA:** Customer Assist queues do not appear in the default `wxcli call-queue list` output. You must pass `--has-cx-essentials true` to see them. Using CX Essentials endpoints on a regular queue returns error 28018 ("CX Essentials is not enabled for this Call center"). The CLI detects this error and prints a tip.
|
|
1715
|
+
|
|
1716
|
+
> **GOTCHA:** Creating a Customer Assist queue requires `callPolicies` in the request body via `--json-body`. Omitting `callPolicies` results in a 400 error. Minimum: `{"callPolicies":{"policy":"SIMULTANEOUS"}}`.
|
|
1717
|
+
|
|
1718
|
+
> **GOTCHA:** `delete-supervisors-config-1` returns 204 but the supervisor persists. Use `update-supervisors` with `action: DELETE` on each agent instead — removing the last agent auto-removes the supervisor.
|
|
1719
|
+
|
|
1720
|
+
---
|
|
1721
|
+
|
|
1722
|
+
## Operating Modes
|
|
1723
|
+
|
|
1724
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
1725
|
+
|
|
1726
|
+
> **Not supported for Webex for Government (FedRAMP).** See [authentication.md → FedRAMP](authentication.md#webex-for-government-fedramp) for all FedRAMP restrictions.
|
|
1727
|
+
|
|
1728
|
+
### Overview
|
|
1729
|
+
|
|
1730
|
+
Operating Modes define time-of-day schedules (business hours, after hours, holidays) that control call routing behavior for features like auto attendants and call queues. They can be defined at the organization level and assigned to locations.
|
|
1731
|
+
|
|
1732
|
+
Types: `SAME_HOURS_DAILY`, `DIFFERENT_HOURS_DAILY`, `HOLIDAY`.
|
|
1733
|
+
|
|
1734
|
+
### Raw HTTP
|
|
1735
|
+
|
|
1736
|
+
```python
|
|
1737
|
+
from wxc_sdk import WebexSimpleApi
|
|
1738
|
+
api = WebexSimpleApi()
|
|
1739
|
+
BASE = "https://webexapis.com/v1"
|
|
1740
|
+
```
|
|
1741
|
+
|
|
1742
|
+
**List Operating Modes** (org-wide):
|
|
1743
|
+
|
|
1744
|
+
```python
|
|
1745
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/operatingModes",
|
|
1746
|
+
params={"name": "Business", "limitToLocationId": loc_id,
|
|
1747
|
+
"limitToOrgLevelEnabled": "true", "order": "ASC", "max": 1000})
|
|
1748
|
+
items = result["operatingModes"] # response key: "operatingModes"
|
|
1749
|
+
# Each item: {id, name}
|
|
1750
|
+
```
|
|
1751
|
+
|
|
1752
|
+
**Get Operating Mode Details:**
|
|
1753
|
+
|
|
1754
|
+
```python
|
|
1755
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/operatingModes/{mode_id}")
|
|
1756
|
+
# Returns full schedule configuration
|
|
1757
|
+
```
|
|
1758
|
+
|
|
1759
|
+
**Create Operating Mode** -- required: `name`, `type`, `level`:
|
|
1760
|
+
|
|
1761
|
+
```python
|
|
1762
|
+
body = {
|
|
1763
|
+
"name": "Business Hours",
|
|
1764
|
+
"type": "SAME_HOURS_DAILY", # SAME_HOURS_DAILY | DIFFERENT_HOURS_DAILY | HOLIDAY
|
|
1765
|
+
"level": "ORGANIZATION", # required: must be ORGANIZATION
|
|
1766
|
+
"locationId": loc_id # optional: scope to a location
|
|
1767
|
+
}
|
|
1768
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/operatingModes/", json=body)
|
|
1769
|
+
mode_id = result["id"]
|
|
1770
|
+
```
|
|
1771
|
+
|
|
1772
|
+
**Update Operating Mode:**
|
|
1773
|
+
|
|
1774
|
+
```python
|
|
1775
|
+
api.session.rest_put(f"{BASE}/telephony/config/operatingModes/{mode_id}",
|
|
1776
|
+
json={"name": "Updated Hours"})
|
|
1777
|
+
```
|
|
1778
|
+
|
|
1779
|
+
**Delete Operating Mode:**
|
|
1780
|
+
|
|
1781
|
+
```python
|
|
1782
|
+
api.session.rest_delete(f"{BASE}/telephony/config/operatingModes/{mode_id}")
|
|
1783
|
+
```
|
|
1784
|
+
|
|
1785
|
+
**Create Holiday** (HOLIDAY type only) -- required: `name`, `startDate`, `endDate`, `allDayEnabled`:
|
|
1786
|
+
|
|
1787
|
+
```python
|
|
1788
|
+
body = {
|
|
1789
|
+
"name": "Christmas 2026",
|
|
1790
|
+
"allDayEnabled": True,
|
|
1791
|
+
"startDate": "2026-12-25", # note: startDate/endDate, not date
|
|
1792
|
+
"endDate": "2026-12-25"
|
|
1793
|
+
}
|
|
1794
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/operatingModes/{mode_id}/holidays", json=body)
|
|
1795
|
+
holiday_id = result["id"]
|
|
1796
|
+
```
|
|
1797
|
+
|
|
1798
|
+
**Get / Update / Delete Holiday:**
|
|
1799
|
+
|
|
1800
|
+
```python
|
|
1801
|
+
# Get
|
|
1802
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/operatingModes/{mode_id}/holidays/{holiday_id}")
|
|
1803
|
+
|
|
1804
|
+
# Update
|
|
1805
|
+
api.session.rest_put(f"{BASE}/telephony/config/operatingModes/{mode_id}/holidays/{holiday_id}",
|
|
1806
|
+
json={"name": "New Year", "startDate": "2027-01-01", "endDate": "2027-01-01", "allDayEnabled": True})
|
|
1807
|
+
|
|
1808
|
+
# Delete
|
|
1809
|
+
api.session.rest_delete(f"{BASE}/telephony/config/operatingModes/{mode_id}/holidays/{holiday_id}")
|
|
1810
|
+
```
|
|
1811
|
+
|
|
1812
|
+
**List Available Operating Modes for Location:**
|
|
1813
|
+
|
|
1814
|
+
```python
|
|
1815
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/operatingModes/availableOperatingModes",
|
|
1816
|
+
params={"max": 1000})
|
|
1817
|
+
items = result["availableOperatingModes"]
|
|
1818
|
+
```
|
|
1819
|
+
|
|
1820
|
+
**Get Operating Mode Call Forward Available Numbers:**
|
|
1821
|
+
|
|
1822
|
+
```python
|
|
1823
|
+
result = api.session.rest_get(
|
|
1824
|
+
f"{BASE}/telephony/config/locations/{loc_id}/operatingModes/callForwarding/availableNumbers",
|
|
1825
|
+
params={"max": 1000})
|
|
1826
|
+
items = result["availableNumbers"]
|
|
1827
|
+
```
|
|
1828
|
+
|
|
1829
|
+
### CLI Examples
|
|
1830
|
+
|
|
1831
|
+
```bash
|
|
1832
|
+
# List operating modes (org-wide)
|
|
1833
|
+
wxcli operating-modes list
|
|
1834
|
+
|
|
1835
|
+
# List operating modes filtered by location
|
|
1836
|
+
wxcli operating-modes list --limit-to-location-id <loc_id>
|
|
1837
|
+
|
|
1838
|
+
# Get details for an operating mode
|
|
1839
|
+
wxcli operating-modes show --operating-mode-id <mode_id>
|
|
1840
|
+
|
|
1841
|
+
# Create an operating mode
|
|
1842
|
+
wxcli operating-modes create --name "Business Hours" --type "SAME_HOURS_DAILY" --level "ORGANIZATION"
|
|
1843
|
+
|
|
1844
|
+
# Update an operating mode
|
|
1845
|
+
wxcli operating-modes update --operating-mode-id <mode_id> --name "Updated Hours"
|
|
1846
|
+
|
|
1847
|
+
# Delete an operating mode
|
|
1848
|
+
wxcli operating-modes delete --operating-mode-id <mode_id>
|
|
1849
|
+
|
|
1850
|
+
# Create a holiday on a HOLIDAY-type operating mode
|
|
1851
|
+
wxcli operating-modes create-holidays --operating-mode-id <mode_id> \
|
|
1852
|
+
--name "Christmas 2026" --all-day-enabled --start-date "2026-12-25" --end-date "2026-12-25"
|
|
1853
|
+
|
|
1854
|
+
# Get holiday details
|
|
1855
|
+
wxcli operating-modes show-holidays --operating-mode-id <mode_id> --holiday-id <holiday_id>
|
|
1856
|
+
|
|
1857
|
+
# Update a holiday
|
|
1858
|
+
wxcli operating-modes update-holidays --operating-mode-id <mode_id> --holiday-id <holiday_id> \
|
|
1859
|
+
--name "New Year" --start-date "2027-01-01" --end-date "2027-01-01"
|
|
1860
|
+
|
|
1861
|
+
# Delete a holiday
|
|
1862
|
+
wxcli operating-modes delete-holidays --operating-mode-id <mode_id> --holiday-id <holiday_id>
|
|
1863
|
+
|
|
1864
|
+
# List available operating modes for a location
|
|
1865
|
+
wxcli operating-modes list-available-operating-modes --location-id <loc_id>
|
|
1866
|
+
|
|
1867
|
+
# Get available call forward numbers for operating modes
|
|
1868
|
+
wxcli operating-modes list-available-numbers --location-id <loc_id>
|
|
1869
|
+
```
|
|
1870
|
+
|
|
1871
|
+
### Gotchas
|
|
1872
|
+
|
|
1873
|
+
- OM create requires `level=ORGANIZATION` -- other values fail.
|
|
1874
|
+
- `type` must be one of: `SAME_HOURS_DAILY`, `DIFFERENT_HOURS_DAILY`, `HOLIDAY`.
|
|
1875
|
+
- `sameHoursDaily` needs actual `DaySchedule` hours configured to take effect.
|
|
1876
|
+
- Holiday create uses `startDate`/`endDate` fields (not `date`), plus `allDayEnabled`.
|
|
1877
|
+
- Holidays can only be added to `HOLIDAY` type operating modes.
|
|
1878
|
+
|
|
1879
|
+
---
|
|
1880
|
+
|
|
1881
|
+
## Call Recording (Org-Level)
|
|
1882
|
+
|
|
1883
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
1884
|
+
|
|
1885
|
+
### Overview
|
|
1886
|
+
|
|
1887
|
+
Organization-level call recording settings control global recording behavior. Per-queue recording is managed through Customer Assist (see above). Per-person recording is managed through person call settings.
|
|
1888
|
+
|
|
1889
|
+
### Raw HTTP
|
|
1890
|
+
|
|
1891
|
+
```python
|
|
1892
|
+
from wxc_sdk import WebexSimpleApi
|
|
1893
|
+
api = WebexSimpleApi()
|
|
1894
|
+
BASE = "https://webexapis.com/v1"
|
|
1895
|
+
```
|
|
1896
|
+
|
|
1897
|
+
**Get Org Call Recording Settings:**
|
|
1898
|
+
|
|
1899
|
+
```python
|
|
1900
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/callRecording")
|
|
1901
|
+
# Returns: enabled, record, vendor info, etc.
|
|
1902
|
+
```
|
|
1903
|
+
|
|
1904
|
+
**Update Org Call Recording Settings:**
|
|
1905
|
+
|
|
1906
|
+
```python
|
|
1907
|
+
api.session.rest_put(f"{BASE}/telephony/config/callRecording",
|
|
1908
|
+
json={"enabled": True})
|
|
1909
|
+
```
|
|
1910
|
+
|
|
1911
|
+
**Get Call Recording Terms of Service:**
|
|
1912
|
+
|
|
1913
|
+
```python
|
|
1914
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/callRecording/vendors/{vendor_id}/termsOfService")
|
|
1915
|
+
```
|
|
1916
|
+
|
|
1917
|
+
### CLI Examples
|
|
1918
|
+
|
|
1919
|
+
```bash
|
|
1920
|
+
# Get org-level call recording settings
|
|
1921
|
+
wxcli call-recording show
|
|
1922
|
+
|
|
1923
|
+
# Update org-level call recording settings
|
|
1924
|
+
wxcli call-recording update --json-body '{"enabled": true}'
|
|
1925
|
+
|
|
1926
|
+
# Get call recording terms of service
|
|
1927
|
+
wxcli call-recording show-terms-of-service --vendor-id <vendor_id>
|
|
1928
|
+
|
|
1929
|
+
# Update call recording terms of service
|
|
1930
|
+
wxcli call-recording update-terms-of-service --vendor-id <vendor_id> --json-body '{"termsOfServiceEnabled": true}'
|
|
1931
|
+
|
|
1932
|
+
# Get org-level compliance announcement settings
|
|
1933
|
+
wxcli call-recording show-compliance-announcement-call-recording
|
|
1934
|
+
|
|
1935
|
+
# Update org-level compliance announcement settings
|
|
1936
|
+
wxcli call-recording update-compliance-announcement-call-recording --json-body '{"enabled": true}'
|
|
1937
|
+
|
|
1938
|
+
# Get location-level compliance announcement settings
|
|
1939
|
+
wxcli call-recording show-compliance-announcement-call-recording-1 --location-id <loc_id>
|
|
1940
|
+
|
|
1941
|
+
# Update location-level compliance announcement settings
|
|
1942
|
+
wxcli call-recording update-compliance-announcement-call-recording-1 --location-id <loc_id> --json-body '{"enabled": true}'
|
|
1943
|
+
|
|
1944
|
+
# List call recording regions
|
|
1945
|
+
wxcli call-recording list
|
|
1946
|
+
|
|
1947
|
+
# List call recording vendors for a location
|
|
1948
|
+
wxcli call-recording list-vendors --location-id <loc_id>
|
|
1949
|
+
|
|
1950
|
+
# Get org-level call recording vendors
|
|
1951
|
+
wxcli call-recording show-vendors
|
|
1952
|
+
|
|
1953
|
+
# Set call recording vendor for a location
|
|
1954
|
+
wxcli call-recording update-vendor-call-recording --location-id <loc_id> --json-body '{"vendorId": "<vendor_id>"}'
|
|
1955
|
+
|
|
1956
|
+
# List call recording jobs
|
|
1957
|
+
wxcli call-recording list-call-recording
|
|
1958
|
+
|
|
1959
|
+
# Get job status of a call recording job
|
|
1960
|
+
wxcli call-recording show-call-recording --job-id <job_id>
|
|
1961
|
+
```
|
|
1962
|
+
|
|
1963
|
+
---
|
|
1964
|
+
|
|
1965
|
+
## Announcements & Playlists
|
|
1966
|
+
|
|
1967
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
1968
|
+
|
|
1969
|
+
### Overview
|
|
1970
|
+
|
|
1971
|
+
The Announcement Repository stores binary audio greeting files (WAV, WMA) used by auto attendants, call queues, hunt groups, and other features. Announcements can be managed at the organization level or scoped to a location. Playlists group multiple announcements for sequential playback.
|
|
1972
|
+
|
|
1973
|
+
### Raw HTTP
|
|
1974
|
+
|
|
1975
|
+
```python
|
|
1976
|
+
from wxc_sdk import WebexSimpleApi
|
|
1977
|
+
api = WebexSimpleApi()
|
|
1978
|
+
BASE = "https://webexapis.com/v1"
|
|
1979
|
+
```
|
|
1980
|
+
|
|
1981
|
+
#### Announcements
|
|
1982
|
+
|
|
1983
|
+
**List Announcements** (org-level, filterable by location):
|
|
1984
|
+
|
|
1985
|
+
```python
|
|
1986
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements",
|
|
1987
|
+
params={"locationId": loc_id, "fileName": "greeting", "fileType": "WAV",
|
|
1988
|
+
"name": "Welcome", "order": "fileName", "max": 1000})
|
|
1989
|
+
items = result["announcements"] # response key: "announcements"
|
|
1990
|
+
# Each item: {id, name, fileName, fileSize, mediaFileType, level, locationId, locationName}
|
|
1991
|
+
```
|
|
1992
|
+
|
|
1993
|
+
**Get Announcement Details:**
|
|
1994
|
+
|
|
1995
|
+
```python
|
|
1996
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements/{ann_id}")
|
|
1997
|
+
# Org-level announcement
|
|
1998
|
+
```
|
|
1999
|
+
|
|
2000
|
+
**Get Location-Level Announcement Details:**
|
|
2001
|
+
|
|
2002
|
+
```python
|
|
2003
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/announcements/{ann_id}")
|
|
2004
|
+
```
|
|
2005
|
+
|
|
2006
|
+
**Update Announcement** (org-level):
|
|
2007
|
+
|
|
2008
|
+
```python
|
|
2009
|
+
api.session.rest_put(f"{BASE}/telephony/config/announcements/{ann_id}", json={...})
|
|
2010
|
+
```
|
|
2011
|
+
|
|
2012
|
+
**Update Announcement** (location-level):
|
|
2013
|
+
|
|
2014
|
+
```python
|
|
2015
|
+
api.session.rest_put(f"{BASE}/telephony/config/locations/{loc_id}/announcements/{ann_id}", json={...})
|
|
2016
|
+
```
|
|
2017
|
+
|
|
2018
|
+
**Delete Announcement** (org-level):
|
|
2019
|
+
|
|
2020
|
+
```python
|
|
2021
|
+
api.session.rest_delete(f"{BASE}/telephony/config/announcements/{ann_id}")
|
|
2022
|
+
```
|
|
2023
|
+
|
|
2024
|
+
**Delete Announcement** (location-level):
|
|
2025
|
+
|
|
2026
|
+
```python
|
|
2027
|
+
api.session.rest_delete(f"{BASE}/telephony/config/locations/{loc_id}/announcements/{ann_id}")
|
|
2028
|
+
```
|
|
2029
|
+
|
|
2030
|
+
**Get Repository Usage** (org-level):
|
|
2031
|
+
|
|
2032
|
+
```python
|
|
2033
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements/usage")
|
|
2034
|
+
items = result["usage"]
|
|
2035
|
+
```
|
|
2036
|
+
|
|
2037
|
+
**Get Repository Usage** (location-level):
|
|
2038
|
+
|
|
2039
|
+
```python
|
|
2040
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/locations/{loc_id}/announcements/usage")
|
|
2041
|
+
items = result["usage"]
|
|
2042
|
+
```
|
|
2043
|
+
|
|
2044
|
+
**Note**: Announcement upload (create) requires multipart/form-data with the binary file. The raw HTTP `rest_post` method may not support file uploads directly -- use the SDK's upload methods or construct multipart requests manually.
|
|
2045
|
+
|
|
2046
|
+
#### Playlists
|
|
2047
|
+
|
|
2048
|
+
**List Playlists:**
|
|
2049
|
+
|
|
2050
|
+
```python
|
|
2051
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements/playlists",
|
|
2052
|
+
params={"max": 1000})
|
|
2053
|
+
items = result["playlists"] # response key: "playlists"
|
|
2054
|
+
```
|
|
2055
|
+
|
|
2056
|
+
**Get Playlist Details:**
|
|
2057
|
+
|
|
2058
|
+
```python
|
|
2059
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements/playlists/{playlist_id}")
|
|
2060
|
+
```
|
|
2061
|
+
|
|
2062
|
+
**Create Playlist:**
|
|
2063
|
+
|
|
2064
|
+
```python
|
|
2065
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/announcements/playlists",
|
|
2066
|
+
json={"name": "Hold Music"})
|
|
2067
|
+
playlist_id = result["id"]
|
|
2068
|
+
```
|
|
2069
|
+
|
|
2070
|
+
**Update Playlist:**
|
|
2071
|
+
|
|
2072
|
+
```python
|
|
2073
|
+
api.session.rest_put(f"{BASE}/telephony/config/announcements/playlists/{playlist_id}",
|
|
2074
|
+
json={"name": "Updated Playlist"})
|
|
2075
|
+
```
|
|
2076
|
+
|
|
2077
|
+
**Delete Playlist:**
|
|
2078
|
+
|
|
2079
|
+
```python
|
|
2080
|
+
api.session.rest_delete(f"{BASE}/telephony/config/announcements/playlists/{playlist_id}")
|
|
2081
|
+
```
|
|
2082
|
+
|
|
2083
|
+
**List Playlist Locations:**
|
|
2084
|
+
|
|
2085
|
+
```python
|
|
2086
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/announcements/playlists/{playlist_id}/locations",
|
|
2087
|
+
params={"max": 1000})
|
|
2088
|
+
items = result["locations"]
|
|
2089
|
+
```
|
|
2090
|
+
|
|
2091
|
+
**Update Playlist Locations:**
|
|
2092
|
+
|
|
2093
|
+
```python
|
|
2094
|
+
api.session.rest_put(f"{BASE}/telephony/config/announcements/playlists/{playlist_id}/locations",
|
|
2095
|
+
json={"locationIds": [loc_id_1, loc_id_2]})
|
|
2096
|
+
```
|
|
2097
|
+
|
|
2098
|
+
### CLI Examples
|
|
2099
|
+
|
|
2100
|
+
#### Announcements
|
|
2101
|
+
|
|
2102
|
+
```bash
|
|
2103
|
+
# List announcements (org-level, optionally filtered by location)
|
|
2104
|
+
wxcli announcements list --location-id <loc_id>
|
|
2105
|
+
|
|
2106
|
+
# Get org-level announcement details
|
|
2107
|
+
wxcli announcements show-announcements-config --announcement-id <ann_id>
|
|
2108
|
+
|
|
2109
|
+
# Get location-level announcement details
|
|
2110
|
+
wxcli announcements show-announcements-locations --location-id <loc_id> --announcement-id <ann_id>
|
|
2111
|
+
|
|
2112
|
+
# Update an org-level announcement
|
|
2113
|
+
wxcli announcements update --announcement-id <ann_id> --json-body '{"name": "Updated Greeting"}'
|
|
2114
|
+
|
|
2115
|
+
# Update a location-level announcement
|
|
2116
|
+
wxcli announcements update-announcements --location-id <loc_id> --announcement-id <ann_id> --json-body '{"name": "Updated"}'
|
|
2117
|
+
|
|
2118
|
+
# Delete an org-level announcement
|
|
2119
|
+
wxcli announcements delete --announcement-id <ann_id>
|
|
2120
|
+
|
|
2121
|
+
# Delete a location-level announcement
|
|
2122
|
+
wxcli announcements delete-announcements --location-id <loc_id> --announcement-id <ann_id>
|
|
2123
|
+
|
|
2124
|
+
# Get org-level repository usage
|
|
2125
|
+
wxcli announcements show
|
|
2126
|
+
|
|
2127
|
+
# Get location-level repository usage
|
|
2128
|
+
wxcli announcements show-usage --location-id <loc_id>
|
|
2129
|
+
```
|
|
2130
|
+
|
|
2131
|
+
#### Playlists
|
|
2132
|
+
|
|
2133
|
+
```bash
|
|
2134
|
+
# List announcement playlists
|
|
2135
|
+
wxcli announcement-playlists list
|
|
2136
|
+
|
|
2137
|
+
# Get playlist details
|
|
2138
|
+
wxcli announcement-playlists show --playlist-id <playlist_id>
|
|
2139
|
+
|
|
2140
|
+
# Create a playlist
|
|
2141
|
+
wxcli announcement-playlists create --name "Hold Music"
|
|
2142
|
+
|
|
2143
|
+
# Update a playlist
|
|
2144
|
+
wxcli announcement-playlists update --playlist-id <playlist_id> --name "Updated Playlist"
|
|
2145
|
+
|
|
2146
|
+
# Delete a playlist
|
|
2147
|
+
wxcli announcement-playlists delete --playlist-id <playlist_id>
|
|
2148
|
+
|
|
2149
|
+
# List playlist locations
|
|
2150
|
+
wxcli announcement-playlists list-playlists --playlist-id <playlist_id>
|
|
2151
|
+
|
|
2152
|
+
# Update playlist locations
|
|
2153
|
+
wxcli announcement-playlists update-playlists --playlist-id <playlist_id> \
|
|
2154
|
+
--json-body '{"locationIds": ["<loc_id_1>", "<loc_id_2>"]}'
|
|
2155
|
+
```
|
|
2156
|
+
|
|
2157
|
+
---
|
|
2158
|
+
|
|
2159
|
+
## Single Number Reach
|
|
2160
|
+
|
|
2161
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
2162
|
+
|
|
2163
|
+
### Overview
|
|
2164
|
+
|
|
2165
|
+
Single Number Reach (Office Anywhere) allows a person to receive calls on alternate phone numbers (mobile, home) when their primary Webex line rings. Calls are forwarded simultaneously or sequentially to the configured numbers.
|
|
2166
|
+
|
|
2167
|
+
### Raw HTTP
|
|
2168
|
+
|
|
2169
|
+
```python
|
|
2170
|
+
from wxc_sdk import WebexSimpleApi
|
|
2171
|
+
api = WebexSimpleApi()
|
|
2172
|
+
BASE = "https://webexapis.com/v1"
|
|
2173
|
+
```
|
|
2174
|
+
|
|
2175
|
+
**Get Single Number Reach Settings for a Person:**
|
|
2176
|
+
|
|
2177
|
+
```python
|
|
2178
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/people/{person_id}/singleNumberReach")
|
|
2179
|
+
# Returns: alertAllNumbersForClickToDialCallsEnabled, numbers[]
|
|
2180
|
+
```
|
|
2181
|
+
|
|
2182
|
+
**Update Single Number Reach Settings for a Person:**
|
|
2183
|
+
|
|
2184
|
+
```python
|
|
2185
|
+
api.session.rest_put(f"{BASE}/telephony/config/people/{person_id}/singleNumberReach",
|
|
2186
|
+
json={"alertAllNumbersForClickToDialCallsEnabled": True})
|
|
2187
|
+
```
|
|
2188
|
+
|
|
2189
|
+
**Create a Single Number Reach Number:**
|
|
2190
|
+
|
|
2191
|
+
```python
|
|
2192
|
+
body = {
|
|
2193
|
+
"phoneNumber": "+14155559999",
|
|
2194
|
+
"enabled": True,
|
|
2195
|
+
"name": "Mobile",
|
|
2196
|
+
"doNotForwardCallsEnabled": False,
|
|
2197
|
+
"answerConfirmationEnabled": True
|
|
2198
|
+
}
|
|
2199
|
+
result = api.session.rest_post(
|
|
2200
|
+
f"{BASE}/telephony/config/people/{person_id}/singleNumberReach/numbers", json=body)
|
|
2201
|
+
```
|
|
2202
|
+
|
|
2203
|
+
**Update a Single Number Reach Number:**
|
|
2204
|
+
|
|
2205
|
+
```python
|
|
2206
|
+
api.session.rest_put(
|
|
2207
|
+
f"{BASE}/telephony/config/people/{person_id}/singleNumberReach/numbers/{number_id}",
|
|
2208
|
+
json={"enabled": False, "name": "Home"})
|
|
2209
|
+
```
|
|
2210
|
+
|
|
2211
|
+
**Delete a Single Number Reach Number:**
|
|
2212
|
+
|
|
2213
|
+
```python
|
|
2214
|
+
api.session.rest_delete(
|
|
2215
|
+
f"{BASE}/telephony/config/people/{person_id}/singleNumberReach/numbers/{number_id}")
|
|
2216
|
+
```
|
|
2217
|
+
|
|
2218
|
+
**Get Available Phone Numbers for Single Number Reach:**
|
|
2219
|
+
|
|
2220
|
+
```python
|
|
2221
|
+
result = api.session.rest_get(
|
|
2222
|
+
f"{BASE}/telephony/config/locations/{loc_id}/singleNumberReach/availableNumbers",
|
|
2223
|
+
params={"max": 1000})
|
|
2224
|
+
items = result["availableNumbers"]
|
|
2225
|
+
```
|
|
2226
|
+
|
|
2227
|
+
### CLI Examples
|
|
2228
|
+
|
|
2229
|
+
```bash
|
|
2230
|
+
# Get single number reach settings for a person
|
|
2231
|
+
wxcli single-number-reach list-single-number-reach --person-id <person_id>
|
|
2232
|
+
|
|
2233
|
+
# Create a single number reach number for a person
|
|
2234
|
+
wxcli single-number-reach create --person-id <person_id> \
|
|
2235
|
+
--json-body '{"phoneNumber": "+14155559999", "enabled": true, "name": "Mobile", "answerConfirmationEnabled": true}'
|
|
2236
|
+
|
|
2237
|
+
# Update single number reach settings for a person
|
|
2238
|
+
wxcli single-number-reach update --person-id <person_id> \
|
|
2239
|
+
--json-body '{"alertAllNumbersForClickToDialCallsEnabled": true}'
|
|
2240
|
+
|
|
2241
|
+
# Update a specific single number reach number
|
|
2242
|
+
wxcli single-number-reach update-numbers --person-id <person_id> --number-id <number_id> \
|
|
2243
|
+
--json-body '{"enabled": false, "name": "Home"}'
|
|
2244
|
+
|
|
2245
|
+
# Delete a single number reach number
|
|
2246
|
+
wxcli single-number-reach delete --person-id <person_id> --number-id <number_id>
|
|
2247
|
+
|
|
2248
|
+
# List available phone numbers for single number reach
|
|
2249
|
+
wxcli single-number-reach list --location-id <loc_id>
|
|
2250
|
+
```
|
|
2251
|
+
|
|
2252
|
+
---
|
|
2253
|
+
|
|
2254
|
+
## Virtual Extensions
|
|
2255
|
+
|
|
2256
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
2257
|
+
|
|
2258
|
+
### Overview
|
|
2259
|
+
|
|
2260
|
+
Virtual Extensions are directory entries with extensions (and optionally phone numbers) that are not tied to a person, workspace, or device. They appear in the dial-by-name directory and can be used for call routing. Virtual Extension Ranges allow bulk creation with a shared prefix.
|
|
2261
|
+
|
|
2262
|
+
### Raw HTTP
|
|
2263
|
+
|
|
2264
|
+
```python
|
|
2265
|
+
from wxc_sdk import WebexSimpleApi
|
|
2266
|
+
api = WebexSimpleApi()
|
|
2267
|
+
BASE = "https://webexapis.com/v1"
|
|
2268
|
+
```
|
|
2269
|
+
|
|
2270
|
+
#### Virtual Extensions
|
|
2271
|
+
|
|
2272
|
+
**List Virtual Extensions** (org-wide, filterable):
|
|
2273
|
+
|
|
2274
|
+
```python
|
|
2275
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/virtualExtensions",
|
|
2276
|
+
params={"locationId": loc_id, "name": "Lobby", "extension": "9000",
|
|
2277
|
+
"orgLevelOnly": "true", "max": 1000})
|
|
2278
|
+
items = result["virtualExtensions"] # response key: "virtualExtensions"
|
|
2279
|
+
# Each item: {id, displayName, firstName, lastName, extension, phoneNumber, locationId, locationName}
|
|
2280
|
+
```
|
|
2281
|
+
|
|
2282
|
+
**Get Virtual Extension Details:**
|
|
2283
|
+
|
|
2284
|
+
```python
|
|
2285
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/virtualExtensions/{ext_id}")
|
|
2286
|
+
```
|
|
2287
|
+
|
|
2288
|
+
**Create Virtual Extension:**
|
|
2289
|
+
|
|
2290
|
+
```python
|
|
2291
|
+
body = {
|
|
2292
|
+
"displayName": "Lobby Directory",
|
|
2293
|
+
"firstName": "Lobby",
|
|
2294
|
+
"lastName": "Directory",
|
|
2295
|
+
"extension": "9000",
|
|
2296
|
+
"phoneNumber": "+14155551000", # optional
|
|
2297
|
+
"locationId": loc_id # optional
|
|
2298
|
+
}
|
|
2299
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/virtualExtensions", json=body)
|
|
2300
|
+
ext_id = result["id"]
|
|
2301
|
+
```
|
|
2302
|
+
|
|
2303
|
+
**Update Virtual Extension:**
|
|
2304
|
+
|
|
2305
|
+
```python
|
|
2306
|
+
api.session.rest_put(f"{BASE}/telephony/config/virtualExtensions/{ext_id}",
|
|
2307
|
+
json={"displayName": "New Name", "extension": "9001"})
|
|
2308
|
+
```
|
|
2309
|
+
|
|
2310
|
+
**Delete Virtual Extension:**
|
|
2311
|
+
|
|
2312
|
+
```python
|
|
2313
|
+
api.session.rest_delete(f"{BASE}/telephony/config/virtualExtensions/{ext_id}")
|
|
2314
|
+
```
|
|
2315
|
+
|
|
2316
|
+
**Get Virtual Extension Settings** (org-level):
|
|
2317
|
+
|
|
2318
|
+
```python
|
|
2319
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/virtualExtensions/settings")
|
|
2320
|
+
# Returns: mode (e.g., "STANDARD")
|
|
2321
|
+
```
|
|
2322
|
+
|
|
2323
|
+
**Update Virtual Extension Settings:**
|
|
2324
|
+
|
|
2325
|
+
```python
|
|
2326
|
+
api.session.rest_put(f"{BASE}/telephony/config/virtualExtensions/settings",
|
|
2327
|
+
json={"mode": "STANDARD"})
|
|
2328
|
+
```
|
|
2329
|
+
|
|
2330
|
+
**Validate External Phone Numbers:**
|
|
2331
|
+
|
|
2332
|
+
```python
|
|
2333
|
+
result = api.session.rest_post(
|
|
2334
|
+
f"{BASE}/telephony/config/virtualExtensions/actions/validateNumbers/invoke",
|
|
2335
|
+
json={"phoneNumbers": ["+14155551234"]})
|
|
2336
|
+
```
|
|
2337
|
+
|
|
2338
|
+
#### Virtual Extension Ranges
|
|
2339
|
+
|
|
2340
|
+
**List Virtual Extension Ranges:**
|
|
2341
|
+
|
|
2342
|
+
```python
|
|
2343
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/virtualExtensionRanges",
|
|
2344
|
+
params={"name": "Sales", "prefix": "90", "locationId": loc_id, "max": 1000})
|
|
2345
|
+
items = result["virtualExtensionRanges"] # response key: "virtualExtensionRanges"
|
|
2346
|
+
```
|
|
2347
|
+
|
|
2348
|
+
**Get Virtual Extension Range Details:**
|
|
2349
|
+
|
|
2350
|
+
```python
|
|
2351
|
+
result = api.session.rest_get(f"{BASE}/telephony/config/virtualExtensionRanges/{range_id}")
|
|
2352
|
+
```
|
|
2353
|
+
|
|
2354
|
+
**Create Virtual Extension Range:**
|
|
2355
|
+
|
|
2356
|
+
```python
|
|
2357
|
+
result = api.session.rest_post(f"{BASE}/telephony/config/virtualExtensionRanges",
|
|
2358
|
+
json={"name": "Sales Range", "prefix": "90", "locationId": loc_id})
|
|
2359
|
+
range_id = result["id"]
|
|
2360
|
+
```
|
|
2361
|
+
|
|
2362
|
+
**Update Virtual Extension Range:**
|
|
2363
|
+
|
|
2364
|
+
```python
|
|
2365
|
+
api.session.rest_put(f"{BASE}/telephony/config/virtualExtensionRanges/{range_id}/",
|
|
2366
|
+
json={"name": "Updated Range", "prefix": "91", "action": "REPLACE"})
|
|
2367
|
+
```
|
|
2368
|
+
|
|
2369
|
+
**Delete Virtual Extension Range:**
|
|
2370
|
+
|
|
2371
|
+
```python
|
|
2372
|
+
api.session.rest_delete(f"{BASE}/telephony/config/virtualExtensionRanges/{range_id}")
|
|
2373
|
+
```
|
|
2374
|
+
|
|
2375
|
+
**Validate Range Prefix:**
|
|
2376
|
+
|
|
2377
|
+
```python
|
|
2378
|
+
result = api.session.rest_post(
|
|
2379
|
+
f"{BASE}/telephony/config/virtualExtensionRanges/actions/validate/invoke",
|
|
2380
|
+
json={"locationId": loc_id, "name": "Test Range", "prefix": "90"})
|
|
2381
|
+
```
|
|
2382
|
+
|
|
2383
|
+
### CLI Examples
|
|
2384
|
+
|
|
2385
|
+
#### Virtual Extensions
|
|
2386
|
+
|
|
2387
|
+
```bash
|
|
2388
|
+
# List virtual extensions (org-wide, filterable)
|
|
2389
|
+
wxcli virtual-extensions list --location-id <loc_id>
|
|
2390
|
+
|
|
2391
|
+
# Get details for a virtual extension
|
|
2392
|
+
wxcli virtual-extensions show --virtual-extension-id <ext_id>
|
|
2393
|
+
|
|
2394
|
+
# Create a virtual extension
|
|
2395
|
+
wxcli virtual-extensions create --display-name "Lobby Directory" --extension "9000" --location-id <loc_id>
|
|
2396
|
+
|
|
2397
|
+
# Update a virtual extension
|
|
2398
|
+
wxcli virtual-extensions update --virtual-extension-id <ext_id> --display-name "New Name"
|
|
2399
|
+
|
|
2400
|
+
# Delete a virtual extension
|
|
2401
|
+
wxcli virtual-extensions delete --virtual-extension-id <ext_id>
|
|
2402
|
+
|
|
2403
|
+
# Get virtual extension settings (org-level)
|
|
2404
|
+
wxcli virtual-extensions show-settings
|
|
2405
|
+
|
|
2406
|
+
# Update virtual extension settings
|
|
2407
|
+
wxcli virtual-extensions update-settings --json-body '{"mode": "STANDARD"}'
|
|
2408
|
+
|
|
2409
|
+
# Validate external phone numbers
|
|
2410
|
+
wxcli virtual-extensions validate-an-external --json-body '{"phoneNumbers": ["+14155551234"]}'
|
|
2411
|
+
```
|
|
2412
|
+
|
|
2413
|
+
#### Virtual Extension Ranges
|
|
2414
|
+
|
|
2415
|
+
```bash
|
|
2416
|
+
# List virtual extension ranges
|
|
2417
|
+
wxcli virtual-extensions list-virtual-extension-ranges --location-id <loc_id>
|
|
2418
|
+
|
|
2419
|
+
# Get details for a virtual extension range
|
|
2420
|
+
wxcli virtual-extensions show-virtual-extension-ranges --virtual-extension-range-id <range_id>
|
|
2421
|
+
|
|
2422
|
+
# Create a virtual extension range
|
|
2423
|
+
wxcli virtual-extensions create-virtual-extension-ranges --name "Sales Range" --prefix "90" --location-id <loc_id>
|
|
2424
|
+
|
|
2425
|
+
# Update a virtual extension range
|
|
2426
|
+
wxcli virtual-extensions update-virtual-extension-ranges --virtual-extension-range-id <range_id> \
|
|
2427
|
+
--json-body '{"name": "Updated Range", "prefix": "91", "action": "REPLACE"}'
|
|
2428
|
+
|
|
2429
|
+
# Delete a virtual extension range
|
|
2430
|
+
wxcli virtual-extensions delete-virtual-extension-ranges --virtual-extension-range-id <range_id>
|
|
2431
|
+
|
|
2432
|
+
# Validate a range prefix
|
|
2433
|
+
wxcli virtual-extensions validate-the-prefix --json-body '{"locationId": "<loc_id>", "name": "Test Range", "prefix": "90"}'
|
|
2434
|
+
```
|
|
2435
|
+
|
|
2436
|
+
---
|
|
2437
|
+
|
|
2438
|
+
## Data Models Quick Reference
|
|
2439
|
+
|
|
2440
|
+
### Shared Models (from `wxc_sdk.common`)
|
|
2441
|
+
|
|
2442
|
+
| Model | Used By | Description |
|
|
2443
|
+
|-------|---------|-------------|
|
|
2444
|
+
| `PersonPlaceAgent` | Call Park, Call Pickup | Person/workspace agent with ID, name, phone, extension, type |
|
|
2445
|
+
| `CallParkExtension` | Call Park, Call Park Extensions | Lightweight model: id, name, extension |
|
|
2446
|
+
| `RingPattern` | Call Park Settings | Enum: ring pattern (e.g., `normal`) |
|
|
2447
|
+
| `UserType` | Paging | Enum for person vs. workspace |
|
|
2448
|
+
| `DirectLineCallerIdName` | Paging, Voicemail Groups | Caller ID name settings (replaces deprecated first/last name) |
|
|
2449
|
+
| `AvailableNumber` | Paging, Voicemail Groups | Available phone number for assignment |
|
|
2450
|
+
| `CallRecordingSetting` | Customer Assist (Queue Recording) | Full call recording configuration (see fields below) |
|
|
2451
|
+
|
|
2452
|
+
#### `CallRecordingSetting` Fields
|
|
2453
|
+
|
|
2454
|
+
| Field | Type | Notes |
|
|
2455
|
+
|-------|------|-------|
|
|
2456
|
+
| `enabled` | `bool` | Enable/disable call recording for the queue |
|
|
2457
|
+
| `record` | `str` | Recording mode: `Always`, `Never`, or `Always with Pause/Resume` |
|
|
2458
|
+
| `record_voicemail_enabled` | `bool` | Whether voicemail messages are recorded |
|
|
2459
|
+
| `start_stop_announcement_enabled` | `bool` | Play recording start/stop announcement to parties |
|
|
2460
|
+
| `notification` | `object` | Notification settings (type, threshold) |
|
|
2461
|
+
| `repeat` | `object` | Repeat notification settings (enabled, interval) |
|
|
2462
|
+
| `service_provider` | `str` | Recording vendor/provider name |
|
|
2463
|
+
| `external_group` | `str` | External group tag for recording categorization |
|
|
2464
|
+
| `external_identifier` | `str` | External identifier for the recording |
|
|
2465
|
+
|
|
2466
|
+
### Feature-Specific Models
|
|
2467
|
+
|
|
2468
|
+
| Model | Module | Description |
|
|
2469
|
+
|-------|--------|-------------|
|
|
2470
|
+
| `Paging`, `PagingAgent` | `telephony.paging` | Paging group and its members |
|
|
2471
|
+
| `CallPark`, `CallParkSettings`, `LocationCallParkSettings` | `telephony.callpark` | Call park group and location-level settings |
|
|
2472
|
+
| `CallParkRecall`, `RecallHuntGroup`, `AvailableRecallHuntGroup` | `telephony.callpark` | Recall behavior when park times out |
|
|
2473
|
+
| `CallPickup`, `PickupNotificationType` | `telephony.callpickup` | Pickup group and notification enums |
|
|
2474
|
+
| `VoicemailGroup`, `VoicemailGroupDetail` | `telephony.voicemail_groups` | Voicemail group list/detail models |
|
|
2475
|
+
| `ScreenPopConfiguration` | `telephony.cx_essentials` | Screen pop settings |
|
|
2476
|
+
| `WrapUpReason`, `WrapUpReasonDetails`, `QueueWrapupReasonSettings` | `telephony.cx_essentials.wrapup_reasons` | Wrap-up reason models |
|
|
2477
|
+
| `AvailableQueue`, `WrapupReasonQueue`, `QueueSettingsReason` | `telephony.cx_essentials.wrapup_reasons` | Queue-related models for wrap-up |
|
|
2478
|
+
|
|
2479
|
+
---
|
|
2480
|
+
|
|
2481
|
+
## Dependencies & Relationships
|
|
2482
|
+
|
|
2483
|
+
```
|
|
2484
|
+
Call Park ──────────── Call Park Extensions (assigned to park groups)
|
|
2485
|
+
|
|
|
2486
|
+
+──── Agents (PersonPlaceAgent: people, workspaces)
|
|
2487
|
+
|
|
|
2488
|
+
+──── Recall Hunt Group (optional: fallback when park times out)
|
|
2489
|
+
|
|
2490
|
+
Call Pickup ─────────── Agents (PersonPlaceAgent: people, workspaces, virtual lines)
|
|
2491
|
+
|
|
2492
|
+
Paging Group ────────── Originators (PagingAgent: who can page)
|
|
2493
|
+
|
|
|
2494
|
+
+──── Targets (PagingAgent: who receives pages, up to 75)
|
|
2495
|
+
|
|
2496
|
+
Voicemail Group ──────── Assigned to auto attendants, call queues, hunt groups
|
|
2497
|
+
|
|
|
2498
|
+
+──── Available Numbers (for primary and fax)
|
|
2499
|
+
|
|
2500
|
+
Customer Assist ─────── Call Queues (screen pop, recording, wrap-up per queue)
|
|
2501
|
+
|
|
|
2502
|
+
+──── Wrap-Up Reasons (org-level, assigned to queues)
|
|
2503
|
+
|
|
|
2504
|
+
+──── Available Agents (Customer Assist or Basic licensed)
|
|
2505
|
+
```
|
|
2506
|
+
|
|
2507
|
+
### Key Dependency Notes
|
|
2508
|
+
|
|
2509
|
+
1. **Call Park requires Call Park Extensions**: You create Call Park Extensions first, then assign them to Call Park groups.
|
|
2510
|
+
2. **Call Park recall requires Hunt Groups**: If using `ALERT_PARKING_USER_FIRST_THEN_HUNT_GROUP` or `ALERT_HUNT_GROUP_ONLY`, a Hunt Group must exist at the location.
|
|
2511
|
+
3. **Customer Assist requires Call Queues**: Screen pop, queue recording, and wrap-up reasons are all per-queue configurations. Call queues must be created first.
|
|
2512
|
+
4. **Customer Assist requires licensing**: The `has_cx_essentials` filter on `available_agents()` distinguishes between Customer Assist and CX Basic licensed agents.
|
|
2513
|
+
5. **Voicemail Groups are location-scoped**: Created within a location, but listed org-wide.
|
|
2514
|
+
6. **Paging Groups are location-scoped**: Created within a location, but can be listed org-wide.
|
|
2515
|
+
7. **ID instability for Call Park and Call Pickup**: The IDs for Call Park and Call Pickup entities change when their names are modified. Always re-fetch the ID after a name change.
|
|
2516
|
+
|
|
2517
|
+
---
|
|
2518
|
+
|
|
2519
|
+
## Gotchas (Cross-Cutting)
|
|
2520
|
+
|
|
2521
|
+
- **ID instability**: Call Park and Call Pickup IDs change when the entity name is modified. Always re-fetch the ID after a name update.
|
|
2522
|
+
- **Agent format differs by feature type** : Hunt Groups and Call Queues take `agents` as `[{"id": "person_id"}]` (array of objects). Call Pickups take `agents` as `["person_id"]` (plain string array). Paging Groups take `targets` and `originators` as plain string arrays. Using `[{"id": ...}]` for pickup or paging returns 400 "Invalid field value: agents/targets". Reads always return full agent objects regardless.
|
|
2523
|
+
- **Location-scoped features listed org-wide**: Paging Groups and Voicemail Groups can be listed org-wide (no `locationId` required), but **Call Parks and Call Pickups require `locationId`** for list operations. `wxcli call-park list` without a location argument returns empty. Must enumerate per-location during cleanup.
|
|
2524
|
+
- **Nested settings require `--json-body`**: Features with complex nested body fields (voicemail group create, call park recall, screen pop, wrap-up settings) need `--json-body` in the CLI because the generator skips deeply nested object/array fields.
|
|
2525
|
+
- **Voicemail Group create is strict**: Requires 7+ fields (name, extension, passcode, languageCode, messageStorage, notifications, faxMessage, transferToNumber, emailCopyOfMessage). The wxc_sdk `VoicemailGroupDetail.for_create()` has a bug (missing `by_alias=True`); use `--json-body` via CLI or `model_dump(by_alias=True)` via SDK.
|
|
2526
|
+
- **Customer Assist requires licensing**: Screen pop, queue recording, and wrap-up reasons require Customer Assist licensing. Call queues must exist before configuring these features. Error 28018 ("CX Essentials is not enabled for this Call center") means the target queue is not a Customer Assist queue.
|
|
2527
|
+
- **CX queue creation requires `callPolicies`**: Creating a Customer Assist queue without `callPolicies` in the request body returns 400. Use `--json-body` with at minimum `{"callPolicies":{"policy":"SIMULTANEOUS"}}`.
|
|
2528
|
+
- **CX queues hidden from default list**: `wxcli call-queue list` does not show Customer Assist queues. Pass `--has-cx-essentials true` to see them.
|
|
2529
|
+
- **Supervisor delete returns 204 but persists**: `delete-supervisors-config-1 --has-cx-essentials true` gets 204 from the API but the supervisor remains. Workaround: use `update-supervisors` with `action: DELETE` on each agent — removing the last agent auto-removes the supervisor.
|
|
2530
|
+
- **Call Park requires recall**: Creating a Call Park without a `recall` option (e.g., `ALERT_PARKING_USER_ONLY`) will be rejected by the API.
|
|
2531
|
+
- **Announcement upload requires multipart/form-data**: The CLI and raw HTTP `rest_post` may not support binary file uploads directly. Use the SDK upload methods or construct multipart requests manually.
|
|
2532
|
+
- **CallPickupGroup AXL creation with members fails on CUCM 15.0.** The `addCallPickupGroup` AXL operation with `<members>` containing `<directoryNumber>` elements fails with a null priority foreign key constraint (`pickupgroupmember.priority`). Workaround: create the pickup group empty, then add members via `updateLine` with `callPickupGroupName` on each member DN. Verified on CUCM 15.0.1.13901(2).
|
|
2533
|
+
- **No native PagingGroup AXL object type.** CUCM does not expose paging groups through AXL (`listPagingGroup`/`getPagingGroup` do not exist). Paging requires third-party systems (InformaCast, Cisco Paging Server). The migration pipeline's `CanonicalPagingGroup` type exists for manual/CSV import but cannot be auto-extracted from CUCM.
|
|
2534
|
+
|
|
2535
|
+
---
|
|
2536
|
+
|
|
2537
|
+
## See Also
|
|
2538
|
+
|
|
2539
|
+
- [Major Call Features](call-features-major.md) -- Auto Attendants, Call Queues, and Hunt Groups (Call Park recall references Hunt Groups; Customer Assist extends Call Queues; Voicemail Groups can be assigned to AA/CQ/HG)
|
|
2540
|
+
- [Call Routing & PSTN](call-routing.md) -- dial plans, trunks, and routing chain (Paging Groups and Voicemail Groups with phone numbers participate in call routing)
|
|
2541
|
+
- [Provisioning Reference](provisioning.md) -- creating locations and users (all features in this doc are location-scoped and require existing locations)
|