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,1318 @@
|
|
|
1
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
2
|
+
|
|
3
|
+
# Reporting & Analytics
|
|
4
|
+
|
|
5
|
+
CDR feed, report templates, report generation/download, and call quality/queue/AA statistics for Webex Calling.
|
|
6
|
+
|
|
7
|
+
## Sources
|
|
8
|
+
|
|
9
|
+
- `wxc_sdk.cdr` — SDK source for Detailed CDR API (`../wxc_sdk_reference/wxc_sdk/cdr/__init__.py`)
|
|
10
|
+
- `wxc_sdk.reports` — SDK source for Reports API (`../wxc_sdk_reference/wxc_sdk/reports/__init__.py`)
|
|
11
|
+
- [Exploring the Webex Calling Reports and Analytics APIs](https://developer.webex.com/blog/exploring-the-webex-calling-reports-and-analytics-apis)
|
|
12
|
+
- [Webex CDR field reference](https://help.webex.com/en-us/article/nmug598/Reports-for-Your-Cloud-Collaboration-Portfolio)
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Required Scopes
|
|
17
|
+
|
|
18
|
+
| Scope | Purpose |
|
|
19
|
+
|-------|---------|
|
|
20
|
+
| `spark-admin:calling_cdr_read` | Access Detailed Call History (CDR feed/stream). Authenticating user must also have the "Webex Calling Detailed Call History API access" admin role enabled in Control Hub. |
|
|
21
|
+
| `analytics:read_all` | Access Report Templates and Reports APIs. Authenticating user must be a read-only or full administrator. |
|
|
22
|
+
| `spark-admin:locations_read` | Filter CDR queries by location name. |
|
|
23
|
+
|
|
24
|
+
**License requirement:** The Reports API requires the **Pro Pack for Cisco Webex** license on the organization.
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## 1. Detailed Call History (CDR) API
|
|
29
|
+
|
|
30
|
+
### Endpoint
|
|
31
|
+
|
|
32
|
+
| Property | Value |
|
|
33
|
+
|----------|-------|
|
|
34
|
+
| Base URL (commercial) | `https://analytics-calling.webexapis.com` |
|
|
35
|
+
| Base URL (government) | `https://analytics-calling-gov.webexapis.com` |
|
|
36
|
+
| CDR Feed path | `/v1/cdr_feed` |
|
|
37
|
+
| CDR Stream path | `/v1/cdr_stream` |
|
|
38
|
+
| Method | `GET` |
|
|
39
|
+
|
|
40
|
+
- **CDR Feed** (`cdr_feed`) — Pull records for a specific time window based on **call start time**. Best for batch/historical pulls. 12-hour max window, 30-day retention.
|
|
41
|
+
- **CDR Stream** (`cdr_stream`) — Returns records based on their **database write time** (when the record was ingested into the Webex Calling cloud), not when the call occurred. 2-hour max window, 12-hour retention. Best for near-real-time monitoring — catches late-arriving records that Feed may miss.
|
|
42
|
+
|
|
43
|
+
**Late-arriving records:** A call placed at 11:59 lasting 10 minutes generates a CDR record around 12:10. CDR Feed querying 11:00–12:00 misses this call (it started in-window but the record didn't exist yet). CDR Stream querying 12:00–13:00 catches it because it queries by write time, not call time.
|
|
44
|
+
|
|
45
|
+
If the region's servers do not host the organization's data, an **HTTP 451** is returned. The response body contains the correct regional endpoint to use instead.
|
|
46
|
+
|
|
47
|
+
### Query Parameters
|
|
48
|
+
|
|
49
|
+
| Parameter | Type | Required | Description |
|
|
50
|
+
|-----------|------|----------|-------------|
|
|
51
|
+
| `startTime` | ISO 8601 datetime | Yes | Start of time window. Feed: call start time. Stream: database write time. |
|
|
52
|
+
| `endTime` | ISO 8601 datetime | Yes | End of time window. Must be after `startTime`. |
|
|
53
|
+
| `locations` | comma-separated strings | No | Location names (as shown in Control Hub). Up to 10. |
|
|
54
|
+
| `max` | int | No | Results per page (pagination). |
|
|
55
|
+
|
|
56
|
+
### Time Range Constraints
|
|
57
|
+
|
|
58
|
+
| Constraint | CDR Feed | CDR Stream |
|
|
59
|
+
|------------|----------|------------|
|
|
60
|
+
| **Timestamp meaning** | Call start time | Database write time |
|
|
61
|
+
| **Max window per request** | 12 hours | 2 hours |
|
|
62
|
+
| **Data retention** | 30 days | 12 hours |
|
|
63
|
+
| **Oldest data** | 30 days ago | 12 hours ago |
|
|
64
|
+
| **Newest data** | ~5 minutes ago | ~1 minute ago |
|
|
65
|
+
|
|
66
|
+
- **Data generation lag:** CDR records may take up to 24 hours after call completion to fully populate. Most appear within 5 minutes.
|
|
67
|
+
- **Late records:** CDR Stream automatically captures late-arriving records via write-time semantics. CDR Feed may miss calls whose records are generated after the queried window closes.
|
|
68
|
+
|
|
69
|
+
### Rate Limits
|
|
70
|
+
|
|
71
|
+
- **1 initial request per minute** per user token.
|
|
72
|
+
- **Up to 10 additional pagination requests per minute** per user token.
|
|
73
|
+
- A 7-day historical pull via CDR Feed requires 14 sequential requests = ~14 minutes. For windows >7 days, consider the Reports API (Detailed Call History template) instead.
|
|
74
|
+
|
|
75
|
+
### Pagination
|
|
76
|
+
|
|
77
|
+
The API returns paginated results via the standard `items` key. The SDK method `session.follow_pagination()` handles automatic page traversal.
|
|
78
|
+
|
|
79
|
+
### SDK Method
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
DetailedCDRApi.get_cdr_history(
|
|
83
|
+
start_time: Union[str, datetime] = None, # Default: ~48 hours ago
|
|
84
|
+
end_time: Union[str, datetime] = None, # Default: ~5 minutes ago
|
|
85
|
+
locations: list[str] = None, # Up to 10 location names
|
|
86
|
+
host: str = 'analytics-calling.webexapis.com',
|
|
87
|
+
stream: bool = False, # True = use cdr_stream instead of cdr_feed
|
|
88
|
+
**params
|
|
89
|
+
) -> Generator[CDR, None, None]
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
When `start_time` and `end_time` are omitted, the SDK defaults to a window of approximately 48 hours ago through 5 minutes ago.
|
|
93
|
+
|
|
94
|
+
**Usage example:**
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from wxc_sdk import WebexSimpleApi
|
|
98
|
+
|
|
99
|
+
api = WebexSimpleApi(tokens='<access_token>')
|
|
100
|
+
|
|
101
|
+
# Pull last 2 hours of CDRs
|
|
102
|
+
from datetime import datetime, timedelta, timezone
|
|
103
|
+
end = datetime.now(timezone.utc) - timedelta(minutes=5)
|
|
104
|
+
start = end - timedelta(hours=2)
|
|
105
|
+
|
|
106
|
+
for cdr in api.cdr.get_cdr_history(start_time=start, end_time=end):
|
|
107
|
+
print(f"{cdr.start_time} | {cdr.direction} | {cdr.calling_number} -> {cdr.called_number} | {cdr.duration}s")
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### CLI Examples
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
# Pull CDR feed for a 2-hour window (batch/historical)
|
|
114
|
+
wxcli cdr list \
|
|
115
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
116
|
+
--end-time "2026-03-17T16:00:00.000Z"
|
|
117
|
+
|
|
118
|
+
# Pull CDR feed filtered by location
|
|
119
|
+
wxcli cdr list \
|
|
120
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
121
|
+
--end-time "2026-03-17T16:00:00.000Z" \
|
|
122
|
+
--locations "San Jose,Austin"
|
|
123
|
+
|
|
124
|
+
# Pull CDR feed with JSON output for scripting
|
|
125
|
+
wxcli cdr list \
|
|
126
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
127
|
+
--end-time "2026-03-17T16:00:00.000Z" \
|
|
128
|
+
-o json
|
|
129
|
+
|
|
130
|
+
# Pull CDR feed with pagination control
|
|
131
|
+
wxcli cdr list \
|
|
132
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
133
|
+
--end-time "2026-03-17T16:00:00.000Z" \
|
|
134
|
+
--max 500 --limit 100
|
|
135
|
+
|
|
136
|
+
# Pull near-real-time CDR stream
|
|
137
|
+
wxcli cdr list-cdr_stream \
|
|
138
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
139
|
+
--end-time "2026-03-17T16:00:00.000Z"
|
|
140
|
+
|
|
141
|
+
# CDR stream filtered by location with JSON output
|
|
142
|
+
wxcli cdr list-cdr_stream \
|
|
143
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
144
|
+
--end-time "2026-03-17T16:00:00.000Z" \
|
|
145
|
+
--locations "Denver" -o json
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### CDR Record Fields
|
|
149
|
+
|
|
150
|
+
The `CDR` model (class `wxc_sdk.cdr.CDR`) contains 55+ fields. Field names arrive from the API in space-separated format (e.g., "Answer time") and are normalized to snake_case by the SDK.
|
|
151
|
+
|
|
152
|
+
#### Core Call Fields
|
|
153
|
+
|
|
154
|
+
| SDK Field | Type | Description |
|
|
155
|
+
|-----------|------|-------------|
|
|
156
|
+
| `start_time` | `datetime` | Call start time (UTC). Answer time may be slightly after. |
|
|
157
|
+
| `answer_time` | `datetime` | Time the call was answered (UTC). |
|
|
158
|
+
| `release_time` | `datetime` | Time the call finished (UTC). |
|
|
159
|
+
| `duration` | `int` | Call length in seconds. |
|
|
160
|
+
| `ring_duration` | `int` | Ringing time before answer/timeout, in seconds. |
|
|
161
|
+
| `hold_duration` | `int` | Total hold time in seconds (floor value). |
|
|
162
|
+
| `answered` | `bool` | Whether this call leg was answered. |
|
|
163
|
+
| `answer_indicator` | `str` | `Yes`, `No`, or `Yes-PostRedirection`. |
|
|
164
|
+
| `direction` | `CDRDirection` | `ORIGINATING` or `TERMINATING`. |
|
|
165
|
+
| `call_type` | `CDRCallType` | See enum values below. |
|
|
166
|
+
| `call_outcome` | `str` | `Success`, `Failure`, or `Refusal`. |
|
|
167
|
+
| `call_outcome_reason` | `str` | Detailed reason (e.g., `Normal`, `UserBusy`, `NoAnswer`, `CallRejected`, `UnassignedNumber`, `SIP408`, `AdminCallBlock`, etc.). |
|
|
168
|
+
| `releasing_party` | `str` | `Local`, `Remote`, or `Unknown`. |
|
|
169
|
+
|
|
170
|
+
#### Number / Identity Fields
|
|
171
|
+
|
|
172
|
+
| SDK Field | Type | Description |
|
|
173
|
+
|-----------|------|-------------|
|
|
174
|
+
| `calling_number` | `str` | Incoming: calling party number. Outgoing: user's number. |
|
|
175
|
+
| `called_number` | `str` | Incoming: user's number. Outgoing: called party number. |
|
|
176
|
+
| `calling_line_id` | `str` | Incoming: calling party line ID. Outgoing: user's line ID. |
|
|
177
|
+
| `called_line_id` | `str` | Incoming: user's line ID. Outgoing: called party line ID. |
|
|
178
|
+
| `dialed_digits` | `str` | Raw keypad digits before pre-translations. Originating calls only. |
|
|
179
|
+
| `user` | `str` | The user who made or received the call. |
|
|
180
|
+
| `user_number` | `str` | User's E.164 number (or extension if no number assigned). |
|
|
181
|
+
| `user_type` | `CDRUserType` | See enum values below. |
|
|
182
|
+
| `user_uuid` | `str` | Unique user identifier across Cisco products. |
|
|
183
|
+
| `caller_id_number` | `str` | Presentation number based on caller ID settings in Control Hub. |
|
|
184
|
+
| `external_caller_id_number` | `str` | Set when external caller ID is location number or org number (not direct line). |
|
|
185
|
+
| `redirecting_number` | `str` | Last redirecting number (for transferred/forwarded calls). |
|
|
186
|
+
| `redirecting_party_uuid` | `str` | UUID of the last redirecting party. |
|
|
187
|
+
| `original_called_party_uuid` | `str` | UUID of the first redirecting party (alias: `Original Called Party UUID`). |
|
|
188
|
+
|
|
189
|
+
#### Session / Correlation IDs
|
|
190
|
+
|
|
191
|
+
| SDK Field | Type | Description |
|
|
192
|
+
|-----------|------|-------------|
|
|
193
|
+
| `call_id` | `str` | SIP Call ID. Share with Cisco TAC for troubleshooting. |
|
|
194
|
+
| `correlation_id` | `str` | Ties together multiple call legs of the same session. |
|
|
195
|
+
| `local_session_id` | `str` | UUID from originating user agent (alias: `local_sessionid`). |
|
|
196
|
+
| `remote_session_id` | `str` | UUID from terminating user agent (alias: `remote_sessionid`). |
|
|
197
|
+
| `final_local_session_id` | `str` | Local Session ID value at call end (alias: `final_local_sessionid`). |
|
|
198
|
+
| `final_remote_session_id` | `str` | Remote Session ID value at call end (alias: `final_remote_sessionid`). |
|
|
199
|
+
| `local_call_id` | `str` | Correlation identity for this CDR. Used with `remote_call_id` to identify the paired CDR of the same call leg: if A.local_call_id = B.remote_call_id AND A.remote_call_id = B.local_call_id, A and B are the two CDRs of the same leg. |
|
|
200
|
+
| `remote_call_id` | `str` | The `local_call_id` value of the other CDR in this call leg. If A.local_call_id = B.remote_call_id, A and B form a leg pair. |
|
|
201
|
+
| `network_call_id` | `str` | Secondary leg-pairing key. If A.network_call_id = B.network_call_id, A and B are the two CDRs of the same call leg. Use this when the local/remote pair is not present (cloud distributes processing internally). |
|
|
202
|
+
| `related_call_id` | `str` | Deflection chaining key. In a deflection (HG ring, forward, redirect), the new leg's ORIGINATING CDR has `related_call_id` = the source leg's TERMINATING CDR's `local_call_id`. This chains each delivery attempt back to the HG/forwarding party. Also used for service activation (recording, executive-assistant) where a new call is spawned. |
|
|
203
|
+
| `transfer_related_call_id` | `str` | Contains the `local_call_id` of a CDR in the **other** call group involved in an attended (consultative) transfer. Linking rule: if CDR1.transfer_related_call_id = CDR2.local_call_id, then CDR1.correlation_id and CDR2.correlation_id belong to the same transfer interaction. Not populated for blind transfers. |
|
|
204
|
+
| `interaction_id` | `str` | Correlates CDRs linked by service interaction (e.g., consult + transfer). |
|
|
205
|
+
|
|
206
|
+
### CDR Data Model — Call Legs and ID Relationships
|
|
207
|
+
|
|
208
|
+
Every call generates one CDR record per **call leg**. A call leg is one participant's perspective of the call. Understanding how legs relate is critical for accurate reporting.
|
|
209
|
+
|
|
210
|
+
#### How legs are generated
|
|
211
|
+
|
|
212
|
+
| Scenario | Legs Generated | Correlation ID |
|
|
213
|
+
|----------|---------------|----------------|
|
|
214
|
+
| **Simple point-to-point call** | 2 legs: ORIGINATING (caller) + TERMINATING (callee) | Same Correlation ID on both legs |
|
|
215
|
+
| **Blind transfer** | Original call: 2 legs. New call to transfer target: 2 new legs with a **new Correlation ID**. `Transfer related call ID` is **not populated**. | Different Correlation ID per call |
|
|
216
|
+
| **Attended (consultative) transfer** | Original call: 2 legs. Consultation call: 2 legs with a new Correlation ID. After transfer completes, the consultation leg's `Transfer related call ID` contains the **Correlation ID of the original call**. | Different Correlation ID per call, linked by `Transfer related call ID` |
|
|
217
|
+
| **Hunt Group / Call Queue** | Inbound call + each HG ring attempt share the **same Correlation ID**. HG itself appears in CDRs as: (1) TERMINATING — the HG "receives" the inbound call; (2) ORIGINATING — the HG "dials" each agent delivery attempt. Each agent attempt produces a HG ORIGINATING CDR + an agent TERMINATING CDR, linked by `related_call_id` = HG's TERMINATING CDR's `local_call_id`. | Same Correlation ID throughout |
|
|
218
|
+
| **Call forwarding (CFA/CFB/CFNA)** | Original call legs + forwarded legs share the same Correlation ID. `Redirect reason` and `Original reason` explain why it was forwarded. | Same Correlation ID |
|
|
219
|
+
| **Call park + retrieve** | Park and retrieve events share the same Correlation ID. `Related reason` = `CallPark` or `CallParkRetrieve`. | Same Correlation ID |
|
|
220
|
+
|
|
221
|
+
#### Key ID relationships
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
Correlation ID ─── groups all legs of ONE call (or one HG/CQ interaction)
|
|
225
|
+
│ A single call involving a transfer produces 2+ Correlation IDs
|
|
226
|
+
│ linked by transfer_related_call_id
|
|
227
|
+
│
|
|
228
|
+
├── local_call_id / remote_call_id ─── identify the two CDRs of one call leg
|
|
229
|
+
│ if A.local_call_id = B.remote_call_id → A and B are the same leg
|
|
230
|
+
│
|
|
231
|
+
├── network_call_id ─── secondary leg-pairing key (use when local/remote pair absent)
|
|
232
|
+
│ if A.network_call_id = B.network_call_id → A and B are the same leg
|
|
233
|
+
│
|
|
234
|
+
├── related_call_id ─── deflection chaining key
|
|
235
|
+
│ ORIGINATING CDR's related_call_id = TERMINATING CDR's local_call_id
|
|
236
|
+
│ Links each HG ring attempt / forward leg back to the source TERMINATING CDR
|
|
237
|
+
│ Also used when a new call is spawned by service activation (recording, exec-assistant)
|
|
238
|
+
│
|
|
239
|
+
├── transfer_related_call_id ─── contains a local_call_id from the OTHER call group
|
|
240
|
+
│ Linking rule: CDR1.transfer_related_call_id = CDR2.local_call_id
|
|
241
|
+
│ → CDR1.correlation_id is linked to CDR2.correlation_id
|
|
242
|
+
│ Present in attended (consultative) transfers; NOT populated for blind transfers
|
|
243
|
+
│
|
|
244
|
+
└── interaction_id ─── correlates CDRs linked by service interaction
|
|
245
|
+
(consult + transfer sequence)
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
#### Transfer Correlation ID linking rule
|
|
249
|
+
|
|
250
|
+
Two Correlation IDs belong to the same transfer interaction when:
|
|
251
|
+
|
|
252
|
+
```
|
|
253
|
+
CDR1.'transfer_related_call_id' = CDR2.'local_call_id'
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
Then CDR1.correlation_id and CDR2.correlation_id are linked. Search for the ultimate destination and CDR correlation must be done across all CDRs sharing any of the linked Correlation IDs. Optionally limit the search to CDR pairs that overlap in time.
|
|
257
|
+
|
|
258
|
+
#### Direction semantics per leg
|
|
259
|
+
|
|
260
|
+
- **ORIGINATING**: The leg from the perspective of the party who **placed** the call (or initiated the delivery/forward).
|
|
261
|
+
- **TERMINATING**: The leg from the perspective of the party who **received** the call (or was the target of the delivery).
|
|
262
|
+
- A single call always produces at least one ORIGINATING and one TERMINATING leg.
|
|
263
|
+
- **Hunt Group CDR pattern**: HG appears in CDRs with `user_type = HuntGroup` in **both** directions:
|
|
264
|
+
- HG TERMINATING — the HG "receives" the inbound call (one per Correlation ID)
|
|
265
|
+
- HG ORIGINATING — the HG "dials" each agent delivery attempt (one per ring attempt)
|
|
266
|
+
- Agent TERMINATING — the agent who receives the ring (one per ring attempt, paired with the HG ORIGINATING above)
|
|
267
|
+
- A HG call with 3 ring attempts produces: 1 inbound ORIGINATING + 1 HG TERMINATING + 3×(HG ORIGINATING + agent TERMINATING) = 8 CDRs total.
|
|
268
|
+
- `Answered=true` on a HuntGroup-type CDR means the HG processed/accepted the call — **not** that a human answered it.
|
|
269
|
+
|
|
270
|
+
#### Answer indicator per leg
|
|
271
|
+
|
|
272
|
+
- `Yes` — this specific leg was answered.
|
|
273
|
+
- `No` — this leg was not answered (rang out, rejected, or redirected before answer).
|
|
274
|
+
- `Yes-PostRedirection` — this leg was answered, but only after being redirected (forwarded/transferred) from another destination.
|
|
275
|
+
- In a hunt group, the HG TERMINATING CDR has `Yes` (HG accepted the call). For agent delivery: only the HG ORIGINATING + agent TERMINATING pair for the answering attempt have `Yes`; all other agent attempts have `No`.
|
|
276
|
+
|
|
277
|
+
#### Ultimate destination rule
|
|
278
|
+
|
|
279
|
+
To find the CDR representing the ultimate answering party:
|
|
280
|
+
|
|
281
|
+
**Simple rule:** `answered=Yes`, `direction=TERMINATING`, and either `user_type=LocalGateway` (on-prem answer) OR the CDR is the only answered TERMINATING CDR for that Correlation ID group.
|
|
282
|
+
|
|
283
|
+
**Robust rule:** `answered=Yes`, `direction=TERMINATING`, AND `local_call_id` is **not** referenced by any `related_call_id` or `transfer_related_call_id` across all linked CDRs. (Handles edge cases where a user forwards or transfers a call that comes back to them.)
|
|
284
|
+
|
|
285
|
+
#### Webhook delivery and deduplication
|
|
286
|
+
|
|
287
|
+
CDR webhooks deliver records every 5 minutes with automatic late-record backfill. Duplicate records may appear in subsequent payloads. Use the `report_id` field as the primary dedup key and `report_time` to determine record freshness.
|
|
288
|
+
|
|
289
|
+
#### Routing / Redirect Fields
|
|
290
|
+
|
|
291
|
+
| SDK Field | Type | Description |
|
|
292
|
+
|-----------|------|-------------|
|
|
293
|
+
| `original_reason` | `CDROriginalReason` | Why call was originally redirected. |
|
|
294
|
+
| `redirect_reason` | `CDRRedirectReason` | Why call was redirected at this step. |
|
|
295
|
+
| `related_reason` | `CDRRelatedReason` | Service-level reason (transfer, forward, park, pickup, etc.). |
|
|
296
|
+
| `route_group` | `str` | Route group for outbound calls via premises PSTN. Originating records only. |
|
|
297
|
+
| `route_list_calls_overage` | `str` | Number of bursting calls over licensed volume (alias: `Route list calls overage`). |
|
|
298
|
+
|
|
299
|
+
#### Client / Device Fields
|
|
300
|
+
|
|
301
|
+
| SDK Field | Type | Description |
|
|
302
|
+
|-----------|------|-------------|
|
|
303
|
+
| `client_type` | `CDRClientType` | See enum values below. |
|
|
304
|
+
| `client_version` | `str` | Client app version. |
|
|
305
|
+
| `os_type` | `str` | Operating system of the app. |
|
|
306
|
+
| `model` | `str` | Device model type. |
|
|
307
|
+
| `device_mac` | `str` | MAC address of the device. |
|
|
308
|
+
| `sub_client_type` | `str` | `MOBILE_NETWORK` for Webex Go calls from mobile. |
|
|
309
|
+
| `device_owner_uuid` | `str` | UUID of device owner (for multi-line/shared line). |
|
|
310
|
+
|
|
311
|
+
#### Location / Organization Fields
|
|
312
|
+
|
|
313
|
+
| SDK Field | Type | Description |
|
|
314
|
+
|-----------|------|-------------|
|
|
315
|
+
| `location` | `str` | Location name for the report. |
|
|
316
|
+
| `site_main_number` | `str` | Main number for the user's site. |
|
|
317
|
+
| `site_timezone` | `str` | Offset in minutes from UTC for user's timezone. |
|
|
318
|
+
| `site_uuid` | `str` | Unique site identifier. |
|
|
319
|
+
| `org_uuid` | `str` | Unique organization identifier across Cisco. |
|
|
320
|
+
| `department_id` | `str` | User's department name identifier. |
|
|
321
|
+
| `authorization_code` | `str` | Auth code for Account/Authorization Codes service. |
|
|
322
|
+
| `international_country` | `str` | Country code of dialed number (international calls only). |
|
|
323
|
+
|
|
324
|
+
#### Trunk Fields
|
|
325
|
+
|
|
326
|
+
| SDK Field | Type | Description |
|
|
327
|
+
|-----------|------|-------------|
|
|
328
|
+
| `inbound_trunk` | `str` | Inbound trunk (present in both Originating and Terminating records). |
|
|
329
|
+
| `outbound_trunk` | `str` | Outbound trunk (present in both Originating and Terminating records). |
|
|
330
|
+
|
|
331
|
+
#### PSTN Vendor Fields
|
|
332
|
+
|
|
333
|
+
| SDK Field | Type | Description |
|
|
334
|
+
|-----------|------|-------------|
|
|
335
|
+
| `pstn_vendor_name` | `str` | PSTN service vendor name for the country. |
|
|
336
|
+
| `pstn_legal_entity` | `str` | Regulated business entity for PSTN. Cisco Calling Plans only. |
|
|
337
|
+
| `pstn_vendor_org_id` | `str` | Cisco Calling plan org UUID (unique across regions). |
|
|
338
|
+
| `pstn_provider_id` | `str` | Immutable Cisco-defined UUID for the PSTN provider. |
|
|
339
|
+
| `external_customer_id` | `str` | External customer identifier. |
|
|
340
|
+
|
|
341
|
+
#### Recording Fields
|
|
342
|
+
|
|
343
|
+
| SDK Field | Type | Description |
|
|
344
|
+
|-----------|------|-------------|
|
|
345
|
+
| `call_recording_platform_name` | `str` | Platform name: `DubberRecorder`, `Webex`, `Eleveo`, `ASCTech`, `MiaRec`, `Imagicle`, or `Unknown`. |
|
|
346
|
+
| `call_recording_result` | `str` | `successful`, `failed`, or `successful but not kept`. |
|
|
347
|
+
| `call_recording_trigger` | `str` | `always`, `always-pause-resume`, `on-demand`, or `on-demand-user-start`. |
|
|
348
|
+
|
|
349
|
+
#### Call Queue / Auto-Attendant Fields
|
|
350
|
+
|
|
351
|
+
| SDK Field | Type | Description |
|
|
352
|
+
|-----------|------|-------------|
|
|
353
|
+
| `queue_type` | `str` | `Customer Assist` or `Call Queue` (alias: `Queue Type`). |
|
|
354
|
+
| `auto_attendant_key_pressed` | `str` | Last DTMF key pressed by caller (alias: `Auto Attendant Key Pressed`). |
|
|
355
|
+
|
|
356
|
+
#### Other Fields
|
|
357
|
+
|
|
358
|
+
| SDK Field | Type | Description |
|
|
359
|
+
|-----------|------|-------------|
|
|
360
|
+
| `report_id` | `str` | Unique ID for deduplication. |
|
|
361
|
+
| `report_time` | `datetime` | Time this CDR record was created (UTC). |
|
|
362
|
+
| `call_transfer_time` | `datetime` | Time the transfer service was invoked (UTC). |
|
|
363
|
+
| `recall_type` | `str` | Indicates call park recall (alias: `Recall Type`). |
|
|
364
|
+
| `answered_elsewhere` | `str` | `Yes` when another agent/user answered (e.g., hunt group simultaneous ring). |
|
|
365
|
+
| `public_calling_ip_address` | `str` | Public IP of calling device (India locations only). |
|
|
366
|
+
| `public_called_ip_address` | `str` | Public IP of called device (India locations only). |
|
|
367
|
+
| `wx_cc_consult_merge_status` | `str` | WxCC consult transfer/conference status: `Yes`, `No`, or `NA`. |
|
|
368
|
+
|
|
369
|
+
#### Caller Reputation Fields
|
|
370
|
+
|
|
371
|
+
| SDK Field | Type | Description |
|
|
372
|
+
|-----------|------|-------------|
|
|
373
|
+
| `caller_reputation_score` | `str` | Score from caller reputation provider (0.0 to 5.0). |
|
|
374
|
+
| `caller_reputation_service_result` | `str` | `allow`, `captcha-allow`, `captcha-block`, or `block`. Terminating CDRs only. |
|
|
375
|
+
| `caller_reputation_score_reason` | `str` | Reason for the reputation score, or error details. |
|
|
376
|
+
|
|
377
|
+
### CDR Enums
|
|
378
|
+
|
|
379
|
+
#### CDRCallType
|
|
380
|
+
|
|
381
|
+
| Value | Meaning |
|
|
382
|
+
|-------|---------|
|
|
383
|
+
| `SIP_MEETING` | Meeting call |
|
|
384
|
+
| `SIP_INTERNATIONAL` | International call |
|
|
385
|
+
| `SIP_SHORTCODE` | Short code call |
|
|
386
|
+
| `SIP_INBOUND` | Inbound SIP call |
|
|
387
|
+
| `SIP_EMERGENCY` | Emergency call |
|
|
388
|
+
| `SIP_PREMIUM` | Premium rate call |
|
|
389
|
+
| `SIP_ENTERPRISE` | Enterprise (on-net) call |
|
|
390
|
+
| `SIP_TOLLFREE` | Toll-free call |
|
|
391
|
+
| `SIP_NATIONAL` | National call |
|
|
392
|
+
| `SIP_MOBILE` | Mobile call |
|
|
393
|
+
| `SIP_URI` | SIP URI call |
|
|
394
|
+
| `SIP_OPERATOR` | Operator-assisted call |
|
|
395
|
+
| `SIP_CLICKTOCALL` | Click-to-call initiated |
|
|
396
|
+
| `ZTN` | Zero-touch notification |
|
|
397
|
+
| `UNKNOWN` | Unknown call type |
|
|
398
|
+
|
|
399
|
+
#### CDRClientType
|
|
400
|
+
|
|
401
|
+
| Value | Meaning |
|
|
402
|
+
|-------|---------|
|
|
403
|
+
| `SIP` | SIP device/endpoint |
|
|
404
|
+
| `WXC_CLIENT` | Webex Calling native client |
|
|
405
|
+
| `WXC_THIRD_PARTY` | Third-party client |
|
|
406
|
+
| `TEAMS_WXC_CLIENT` | Teams with Webex Calling client |
|
|
407
|
+
| `TEAMS_CLIENT` | Microsoft Teams client |
|
|
408
|
+
| `TEAMS_DEVICE` | Microsoft Teams device |
|
|
409
|
+
| `TEAMS_SHARE` | Microsoft Teams shared device |
|
|
410
|
+
| `CLOUD_AWARE_SIP` | Cloud-aware SIP endpoint |
|
|
411
|
+
| `WXC_DEVICE` | Webex Calling device |
|
|
412
|
+
| `WXC_SIP_GW` | Webex Calling SIP gateway |
|
|
413
|
+
|
|
414
|
+
#### CDRDirection
|
|
415
|
+
|
|
416
|
+
| Value | Meaning |
|
|
417
|
+
|-------|---------|
|
|
418
|
+
| `ORIGINATING` | Outbound call |
|
|
419
|
+
| `TERMINATING` | Inbound call |
|
|
420
|
+
|
|
421
|
+
#### CDROriginalReason
|
|
422
|
+
|
|
423
|
+
Values: `Unconditional`, `NoAnswer`, `CallQueue`, `HuntGroup`, `TimeOfDay`, `UserBusy`, `FollowMe`, `Unrecognised`, `Deflection`, `Unavailable`, `Unknown`
|
|
424
|
+
|
|
425
|
+
#### CDRRedirectReason
|
|
426
|
+
|
|
427
|
+
Values: `Unconditional`, `NoAnswer`, `CallQueue`, `TimeOfDay`, `UserBusy`, `FollowMe`, `HuntGroup`, `Deflection`, `Unknown`, `Unavailable`
|
|
428
|
+
|
|
429
|
+
#### CDRRelatedReason
|
|
430
|
+
|
|
431
|
+
Values: `ConsultativeTransfer`, `CallForwardSelective`, `CallForwardAlways`, `CallForwardNoAnswer`, `CallForwardBusy`, `CallForwardNotReachable`, `CallForwardModeBased`, `CallPark`, `CallParkRetrieve`, `CallQueue`, `CallPickup`, `DirectedCallPickup`, `CallRetrieve`, `CallRecording`, `Deflection`, `FaxDeposit`, `HuntGroup`, `PushNotificationRetrieval`, `VoiceXMLScriptTermination`, `AnywhereLocation`, `AnywherePortal`, `Executive`, `ExecutiveAssistantInitiateCall`, `ExecutiveAssistantDivert`, `ExecutiveAssistantCallPush`, `ExecutiveForward`, `RemoteOffice`, `RoutePoint`, `SequentialRing`, `SimultaneousRingPersonal`, `CCMonitoringBI`, `BargeIn`, `Unrecognised`
|
|
432
|
+
|
|
433
|
+
#### CDRUserType
|
|
434
|
+
|
|
435
|
+
Values: `AutomatedAttendantVideo`, `Anchor`, `BroadworksAnywhere`, `VoiceMailRetrieval`, `LocalGateway`, `HuntGroup`, `GroupPaging`, `User`, `VoiceMailGroup`, `CallCenterStandard`, `CallCenterPremium`, `VoiceXML`, `RoutePoint`, `VirtualLine`, `Place`, `RouteList`
|
|
436
|
+
|
|
437
|
+
---
|
|
438
|
+
|
|
439
|
+
## 2. Report Templates API
|
|
440
|
+
|
|
441
|
+
Report templates define the available report types. You must list templates to get the `templateId` needed to create a report.
|
|
442
|
+
|
|
443
|
+
### SDK Method
|
|
444
|
+
|
|
445
|
+
```python
|
|
446
|
+
ReportsApi.list_templates() -> list[ReportTemplate]
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**REST equivalent:** `GET https://webexapis.com/v1/report/templates`
|
|
450
|
+
|
|
451
|
+
### ReportTemplate Model
|
|
452
|
+
|
|
453
|
+
```python
|
|
454
|
+
class ReportTemplate(ApiModel):
|
|
455
|
+
id: Optional[int] # Unique template identifier (API key: "Id")
|
|
456
|
+
title: Optional[str] # Template name
|
|
457
|
+
service: Optional[str] # Service name (e.g., "Webex Calling")
|
|
458
|
+
max_days: Optional[int] # Maximum date range allowed
|
|
459
|
+
start_date: Optional[date] # Earliest available data date
|
|
460
|
+
end_date: Optional[date] # Latest available data date
|
|
461
|
+
identifier: Optional[str] # Template reference key
|
|
462
|
+
validations: Optional[list[ValidationRules]] # Required fields for report creation
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
### Standard Webex Calling Report Templates
|
|
466
|
+
|
|
467
|
+
| Template Name | Description | Key Metrics |
|
|
468
|
+
|---------------|-------------|-------------|
|
|
469
|
+
| **Detailed Call History** | Comprehensive call log with timestamps, duration, status, parties | All CDR fields (see Section 1) |
|
|
470
|
+
| **Calling Media Quality** | Per-call-leg quality measurements | Latency, jitter, packet loss |
|
|
471
|
+
| **Calling Engagement** | Usage and adoption tracking | Call volume, usage patterns, adoption rates over time |
|
|
472
|
+
| **Calling Quality** | Client-side quality from Webex Calling app | Jitter, latency, packet loss (client perspective) |
|
|
473
|
+
| **Call Queue Stats** | Queue-level performance metrics | Incoming calls, wait times, abandonment rates, handling efficiency |
|
|
474
|
+
| **Call Queue Agent Stats** | Per-agent queue performance | Calls handled, average handle time, service level achievements |
|
|
475
|
+
| **Auto-attendant Stats Summary** | AA call volume and menu usage | Call volume, handling metrics, caller menu selections |
|
|
476
|
+
| **Auto-attendant Business & After-Hours Key Details** | AA interaction patterns by time period | Business hours vs. after-hours key press patterns |
|
|
477
|
+
|
|
478
|
+
**Note:** Template IDs are dynamic and may vary by organization. Always use `list_templates()` (or the `GET /report/templates` endpoint) to discover IDs at runtime. The OpenAPI spec example shows ID 130, but actual IDs should not be hardcoded.
|
|
479
|
+
|
|
480
|
+
### CLI Examples
|
|
481
|
+
|
|
482
|
+
```bash
|
|
483
|
+
# List all available report templates (JSON output)
|
|
484
|
+
wxcli report-templates show
|
|
485
|
+
|
|
486
|
+
# List report templates in table format
|
|
487
|
+
wxcli report-templates show -o table
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
### Usage Example
|
|
491
|
+
|
|
492
|
+
```python
|
|
493
|
+
templates = api.reports.list_templates()
|
|
494
|
+
calling_templates = [t for t in templates if t.service and 'Calling' in t.service]
|
|
495
|
+
for t in calling_templates:
|
|
496
|
+
print(f"ID: {t.id} | {t.title} | max {t.max_days} days")
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
---
|
|
500
|
+
|
|
501
|
+
## 3. Reports API
|
|
502
|
+
|
|
503
|
+
Create, list, poll, download, and delete generated reports. Reports are CSV files delivered as ZIP archives.
|
|
504
|
+
|
|
505
|
+
### Constraints
|
|
506
|
+
|
|
507
|
+
- **Maximum 50 reports** can exist at any time. Delete old reports to free quota.
|
|
508
|
+
- Each report can be downloaded up to 30 times.
|
|
509
|
+
- CSV reports for Webex services are only supported for **North American** organizations. Other regions return blank CSVs for Webex-service reports.
|
|
510
|
+
- Reports are delivered in **ZIP format** (Content-Type: `application/zip` or `application/octet-stream`).
|
|
511
|
+
|
|
512
|
+
### CLI Examples
|
|
513
|
+
|
|
514
|
+
```bash
|
|
515
|
+
# Create a report from a template (e.g., template ID 130 = Call Queue Stats)
|
|
516
|
+
wxcli reports create --template-id 130 \
|
|
517
|
+
--start-date "2026-03-01" --end-date "2026-03-15"
|
|
518
|
+
|
|
519
|
+
# Create a Detailed Call History report
|
|
520
|
+
wxcli reports create --template-id 25 \
|
|
521
|
+
--start-date "2026-03-01" --end-date "2026-03-07"
|
|
522
|
+
|
|
523
|
+
# Create a report using full JSON body
|
|
524
|
+
wxcli reports create --json-body '{"templateId": 130, "startDate": "2026-03-01", "endDate": "2026-03-15"}'
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Note:** The CLI `reports` group has `list`, `create`, `show` (poll status/get download URL), and `delete`. To download report CSVs after getting the `downloadURL` from `wxcli reports show`, use `curl` or the SDK `ReportsApi.download()` method.
|
|
528
|
+
|
|
529
|
+
### Create a Report
|
|
530
|
+
|
|
531
|
+
```python
|
|
532
|
+
ReportsApi.create(
|
|
533
|
+
template_id: int, # From list_templates()
|
|
534
|
+
start_date: date = None, # Data start date (YYYY-MM-DD)
|
|
535
|
+
end_date: date = None, # Data end date (YYYY-MM-DD)
|
|
536
|
+
site_list: str = None # Required for site-based templates (Webex Meetings)
|
|
537
|
+
) -> str # Returns report ID
|
|
538
|
+
```
|
|
539
|
+
|
|
540
|
+
**REST equivalent:** `POST https://webexapis.com/v1/reports`
|
|
541
|
+
|
|
542
|
+
**Request body:**
|
|
543
|
+
```json
|
|
544
|
+
{
|
|
545
|
+
"templateId": 130,
|
|
546
|
+
"startDate": "2024-02-01",
|
|
547
|
+
"endDate": "2024-02-05"
|
|
548
|
+
}
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
**Response:**
|
|
552
|
+
```json
|
|
553
|
+
{
|
|
554
|
+
"items": {
|
|
555
|
+
"Id": "Y2lz...ZA"
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
### List Reports
|
|
561
|
+
|
|
562
|
+
```python
|
|
563
|
+
ReportsApi.list(
|
|
564
|
+
report_id: str = None, # Filter by report ID
|
|
565
|
+
service: str = None, # Filter by service name
|
|
566
|
+
template_id: str = None, # Filter by template ID
|
|
567
|
+
from_date: date = None, # Reports created on or after this date
|
|
568
|
+
to_date: date = None # Reports created before this date
|
|
569
|
+
) -> Generator[Report, None, None]
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
**REST equivalent:** `GET https://webexapis.com/v1/reports`
|
|
573
|
+
|
|
574
|
+
Note: `from_date` and `to_date` must be provided together.
|
|
575
|
+
|
|
576
|
+
### Get Report Details (Poll Status)
|
|
577
|
+
|
|
578
|
+
```python
|
|
579
|
+
ReportsApi.details(
|
|
580
|
+
report_id: str # Report ID from create()
|
|
581
|
+
) -> Report
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
**REST equivalent:** `GET https://webexapis.com/v1/reports/{reportId}`
|
|
585
|
+
|
|
586
|
+
### Report Model
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
class Report(ApiModel):
|
|
590
|
+
id: Optional[str] # Report identifier (API key: "Id")
|
|
591
|
+
title: Optional[str] # Report template name
|
|
592
|
+
service: Optional[str] # Service name
|
|
593
|
+
start_date: Optional[date] # Data range start
|
|
594
|
+
end_date: Optional[date] # Data range end
|
|
595
|
+
site_list: Optional[str] # Site (Webex Meetings only)
|
|
596
|
+
created: Optional[datetime] # Creation timestamp
|
|
597
|
+
created_by: Optional[str] # Creator's user ID
|
|
598
|
+
schedule_from: Optional[str] # "api" or "controlHub"
|
|
599
|
+
status: Optional[str] # "done" or "In progress"
|
|
600
|
+
download_domain: Optional[str] # Download host
|
|
601
|
+
download_url: Optional[str] # Full download URL (API key: "downloadURL")
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Status values:**
|
|
605
|
+
- `"done"` — Report is ready for download. `download_url` is populated.
|
|
606
|
+
- `"In progress"` — Report is still generating. Poll again.
|
|
607
|
+
|
|
608
|
+
### Download a Report
|
|
609
|
+
|
|
610
|
+
```python
|
|
611
|
+
ReportsApi.download(
|
|
612
|
+
url: str # The download_url from Report details
|
|
613
|
+
) -> Generator[dict, None, None]
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
The SDK handles:
|
|
617
|
+
1. Authenticated GET request to the download URL
|
|
618
|
+
2. Reading the ZIP archive from the response
|
|
619
|
+
3. Extracting the first CSV file
|
|
620
|
+
4. Skipping the UTF-8 BOM (3 bytes)
|
|
621
|
+
5. Parsing CSV rows into dicts via `csv.DictReader`
|
|
622
|
+
6. Yielding each row as a `dict`
|
|
623
|
+
|
|
624
|
+
### Delete a Report
|
|
625
|
+
|
|
626
|
+
```python
|
|
627
|
+
ReportsApi.delete(
|
|
628
|
+
report_id: str # Report ID to remove
|
|
629
|
+
)
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**REST equivalent:** `DELETE https://webexapis.com/v1/reports/{reportId}`
|
|
633
|
+
|
|
634
|
+
### CallingCDR — Typed Report Download
|
|
635
|
+
|
|
636
|
+
For Detailed Call History reports specifically, use `CallingCDR.from_dicts()` to get typed CDR objects instead of raw dicts:
|
|
637
|
+
|
|
638
|
+
```python
|
|
639
|
+
from wxc_sdk.reports import CallingCDR
|
|
640
|
+
|
|
641
|
+
# Get the download URL from a completed report
|
|
642
|
+
report = api.reports.details(report_id='<id>')
|
|
643
|
+
assert report.status == 'done'
|
|
644
|
+
|
|
645
|
+
# Download and parse into typed CDR objects
|
|
646
|
+
cdrs = list(CallingCDR.from_dicts(api.reports.download(url=report.download_url)))
|
|
647
|
+
for cdr in cdrs:
|
|
648
|
+
print(f"{cdr.start_time} | {cdr.user} | {cdr.duration}s | {cdr.call_outcome}")
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
`CallingCDR` extends `CDR` — all 55+ fields from Section 1 are available.
|
|
652
|
+
|
|
653
|
+
---
|
|
654
|
+
|
|
655
|
+
## 4. Complete Workflow: Generate and Download a Report
|
|
656
|
+
|
|
657
|
+
### CLI Workflow
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
# Step 1: Discover available templates
|
|
661
|
+
wxcli report-templates show -o json
|
|
662
|
+
|
|
663
|
+
# Step 2: Create the report (use the template ID from step 1)
|
|
664
|
+
wxcli reports create --template-id 130 \
|
|
665
|
+
--start-date "2026-03-01" --end-date "2026-03-15"
|
|
666
|
+
# Note the report ID from the response
|
|
667
|
+
|
|
668
|
+
# Step 3: Poll until status is "done"
|
|
669
|
+
wxcli reports show REPORT_ID -o json
|
|
670
|
+
# Look for "status": "done" and "downloadURL" in the response
|
|
671
|
+
|
|
672
|
+
# Step 4: Download the CSV ZIP from the downloadURL
|
|
673
|
+
# Use curl or the SDK ReportsApi.download() method
|
|
674
|
+
|
|
675
|
+
# Step 5: Delete the report to free quota (max 50 reports)
|
|
676
|
+
wxcli reports delete REPORT_ID --force
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
### SDK Workflow
|
|
680
|
+
|
|
681
|
+
```python
|
|
682
|
+
from wxc_sdk import WebexSimpleApi
|
|
683
|
+
from datetime import date
|
|
684
|
+
import time
|
|
685
|
+
|
|
686
|
+
api = WebexSimpleApi(tokens='<access_token>')
|
|
687
|
+
|
|
688
|
+
# Step 1: Find the template
|
|
689
|
+
templates = api.reports.list_templates()
|
|
690
|
+
cq_template = next(t for t in templates if t.title and 'Call Queue Stats' in t.title)
|
|
691
|
+
print(f"Using template: {cq_template.id} — {cq_template.title} (max {cq_template.max_days} days)")
|
|
692
|
+
|
|
693
|
+
# Step 2: Create the report
|
|
694
|
+
report_id = api.reports.create(
|
|
695
|
+
template_id=cq_template.id,
|
|
696
|
+
start_date=date(2024, 2, 1),
|
|
697
|
+
end_date=date(2024, 2, 28)
|
|
698
|
+
)
|
|
699
|
+
print(f"Report created: {report_id}")
|
|
700
|
+
|
|
701
|
+
# Step 3: Poll until done
|
|
702
|
+
while True:
|
|
703
|
+
report = api.reports.details(report_id=report_id)
|
|
704
|
+
print(f"Status: {report.status}")
|
|
705
|
+
if report.status == 'done':
|
|
706
|
+
break
|
|
707
|
+
time.sleep(30)
|
|
708
|
+
|
|
709
|
+
# Step 4: Download
|
|
710
|
+
rows = list(api.reports.download(url=report.download_url))
|
|
711
|
+
print(f"Downloaded {len(rows)} rows")
|
|
712
|
+
|
|
713
|
+
# Step 5: Clean up (free the 50-report quota)
|
|
714
|
+
api.reports.delete(report_id=report_id)
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
---
|
|
718
|
+
|
|
719
|
+
## 5. CDR Feed vs. Reports API — When to Use Which
|
|
720
|
+
|
|
721
|
+
| Criteria | CDR Feed API | Reports API |
|
|
722
|
+
|----------|-------------|-------------|
|
|
723
|
+
| **Data freshness** | Near real-time (5-minute delay) | Batch (async generation) |
|
|
724
|
+
| **Time range** | Last 30 days, 12-hour window per request | Depends on template `max_days` |
|
|
725
|
+
| **Output format** | JSON (paginated) | CSV in ZIP archive |
|
|
726
|
+
| **Use case** | Live dashboards, recent call lookup, alerting | Historical analysis, scheduled reports, compliance |
|
|
727
|
+
| **Rate limit** | 1 req/min + 10 pagination/min | Standard Webex API limits |
|
|
728
|
+
| **Scope** | `spark-admin:calling_cdr_read` | `analytics:read_all` |
|
|
729
|
+
| **License** | Admin role required | Pro Pack required |
|
|
730
|
+
| **Data fields** | 55+ CDR fields (JSON) | Varies by template (CSV columns) |
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
## 6. Use Cases
|
|
735
|
+
|
|
736
|
+
### Call Quality Monitoring
|
|
737
|
+
|
|
738
|
+
Use the **CDR Feed** for near-real-time monitoring, or the **Calling Media Quality** / **Calling Quality** report templates for historical analysis.
|
|
739
|
+
|
|
740
|
+
```bash
|
|
741
|
+
# Pull recent CDR records to check for failures (adjust times to last hour)
|
|
742
|
+
wxcli cdr list \
|
|
743
|
+
--start-time "2026-03-17T15:00:00.000Z" \
|
|
744
|
+
--end-time "2026-03-17T16:00:00.000Z" -o json
|
|
745
|
+
|
|
746
|
+
# Create a Calling Media Quality report for historical analysis
|
|
747
|
+
wxcli reports create --template-id 26 \
|
|
748
|
+
--start-date "2026-03-01" --end-date "2026-03-15"
|
|
749
|
+
```
|
|
750
|
+
|
|
751
|
+
```python
|
|
752
|
+
# Find calls with poor outcomes in the last hour
|
|
753
|
+
from datetime import datetime, timedelta, timezone
|
|
754
|
+
|
|
755
|
+
end = datetime.now(timezone.utc) - timedelta(minutes=5)
|
|
756
|
+
start = end - timedelta(hours=1)
|
|
757
|
+
|
|
758
|
+
failed_calls = [
|
|
759
|
+
cdr for cdr in api.cdr.get_cdr_history(start_time=start, end_time=end)
|
|
760
|
+
if cdr.call_outcome in ('Failure', 'Refusal')
|
|
761
|
+
]
|
|
762
|
+
for c in failed_calls:
|
|
763
|
+
print(f"{c.start_time} | {c.user} | {c.call_outcome}: {c.call_outcome_reason}")
|
|
764
|
+
```
|
|
765
|
+
|
|
766
|
+
### Agent Performance (Call Queue Agent Stats)
|
|
767
|
+
|
|
768
|
+
Generate a **Call Queue Agent Stats** report:
|
|
769
|
+
|
|
770
|
+
```bash
|
|
771
|
+
# Create a Call Queue Agent Stats report
|
|
772
|
+
wxcli reports create --template-id 131 \
|
|
773
|
+
--start-date "2026-02-01" --end-date "2026-02-28"
|
|
774
|
+
```
|
|
775
|
+
|
|
776
|
+
```python
|
|
777
|
+
agent_template = next(t for t in templates if t.title and 'Agent Stats' in t.title)
|
|
778
|
+
report_id = api.reports.create(
|
|
779
|
+
template_id=agent_template.id,
|
|
780
|
+
start_date=date(2024, 2, 1),
|
|
781
|
+
end_date=date(2024, 2, 28)
|
|
782
|
+
)
|
|
783
|
+
# Poll, download, analyze per-agent metrics
|
|
784
|
+
```
|
|
785
|
+
|
|
786
|
+
### Queue Analytics (Call Queue Stats)
|
|
787
|
+
|
|
788
|
+
Generate a **Call Queue Stats** report for queue-level KPIs: incoming call volume, wait times, abandonment rates, handling efficiency.
|
|
789
|
+
|
|
790
|
+
```bash
|
|
791
|
+
# Create a Call Queue Stats report
|
|
792
|
+
wxcli reports create --template-id 130 \
|
|
793
|
+
--start-date "2026-02-01" --end-date "2026-02-28"
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### Auto-Attendant Analytics
|
|
797
|
+
|
|
798
|
+
Use **Auto-attendant Stats Summary** for overall AA performance, or **Auto-attendant Business & After-Hours Key Details** to analyze DTMF key press patterns across business hours vs. after-hours.
|
|
799
|
+
|
|
800
|
+
The CDR field `auto_attendant_key_pressed` is also available in real-time CDR records.
|
|
801
|
+
|
|
802
|
+
```bash
|
|
803
|
+
# Create an Auto-Attendant Stats Summary report
|
|
804
|
+
wxcli reports create --template-id 132 \
|
|
805
|
+
--start-date "2026-02-01" --end-date "2026-02-28"
|
|
806
|
+
```
|
|
807
|
+
|
|
808
|
+
### Billing / Cost Analysis
|
|
809
|
+
|
|
810
|
+
Filter CDR records by `call_type` to separate international, toll-free, premium, and national calls:
|
|
811
|
+
|
|
812
|
+
```python
|
|
813
|
+
international = [
|
|
814
|
+
cdr for cdr in api.cdr.get_cdr_history(start_time=start, end_time=end)
|
|
815
|
+
if cdr.call_type and cdr.call_type.value == 'SIP_INTERNATIONAL'
|
|
816
|
+
]
|
|
817
|
+
```
|
|
818
|
+
|
|
819
|
+
PSTN vendor fields (`pstn_vendor_name`, `pstn_legal_entity`, `pstn_provider_id`) provide carrier-level detail for cost attribution.
|
|
820
|
+
|
|
821
|
+
```bash
|
|
822
|
+
# Pull CDR records and filter by international calls using JSON output + jq
|
|
823
|
+
wxcli cdr list \
|
|
824
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
825
|
+
--end-time "2026-03-17T16:00:00.000Z" -o json
|
|
826
|
+
```
|
|
827
|
+
|
|
828
|
+
### Call Recording Audit
|
|
829
|
+
|
|
830
|
+
Filter by recording fields to audit recording compliance:
|
|
831
|
+
|
|
832
|
+
```bash
|
|
833
|
+
# Pull CDR records to audit recording outcomes
|
|
834
|
+
wxcli cdr list \
|
|
835
|
+
--start-time "2026-03-17T14:00:00.000Z" \
|
|
836
|
+
--end-time "2026-03-17T16:00:00.000Z" -o json
|
|
837
|
+
|
|
838
|
+
# List calling recordings to check status
|
|
839
|
+
wxcli recordings list --service-type calling --status available
|
|
840
|
+
|
|
841
|
+
# Get recording audit summaries for compliance review
|
|
842
|
+
wxcli recording-report list \
|
|
843
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-17T00:00:00Z"
|
|
844
|
+
```
|
|
845
|
+
|
|
846
|
+
```python
|
|
847
|
+
failed_recordings = [
|
|
848
|
+
cdr for cdr in api.cdr.get_cdr_history(start_time=start, end_time=end)
|
|
849
|
+
if cdr.call_recording_result == 'failed'
|
|
850
|
+
]
|
|
851
|
+
```
|
|
852
|
+
|
|
853
|
+
---
|
|
854
|
+
|
|
855
|
+
## 7. Known API Documentation Bugs (from SDK source)
|
|
856
|
+
|
|
857
|
+
The SDK source code flags several discrepancies between Webex API documentation and actual behavior:
|
|
858
|
+
|
|
859
|
+
1. **Report Templates response:** Documentation says `"Template Attributes"` but actual key is `"items"`.
|
|
860
|
+
2. **Report Templates `id` field:** Documentation says `"id"` but actual key is `"Id"`.
|
|
861
|
+
3. **Report Templates missing fields:** `startDate` and `endDate` are not documented but are returned.
|
|
862
|
+
4. **Report Templates validations:** Documentation nests as `"validations"/"validations"` but actual structure is flat `"validations"`.
|
|
863
|
+
5. **List Reports response:** Documentation says `"Report Attributes"` but actual key is `"items"`.
|
|
864
|
+
6. **List Reports `scheduledFrom`:** Documentation says `"scheduledFrom"` but actual key is `"scheduleFrom"`.
|
|
865
|
+
7. **List Reports missing field:** `downloadDomain` is returned but not documented.
|
|
866
|
+
8. **Create Report response:** Actual response is `{"items": {"Id": "..."}}`, not documented structure.
|
|
867
|
+
|
|
868
|
+
---
|
|
869
|
+
|
|
870
|
+
## 8. Gotchas
|
|
871
|
+
|
|
872
|
+
- **Regional routing:** If the CDR endpoint returns HTTP 451, parse the response body for the correct regional endpoint URL and retry.
|
|
873
|
+
- **12-hour window limit:** CDR Feed requests cannot span more than 12 hours. For longer ranges, issue multiple sequential requests.
|
|
874
|
+
- **Empty/NA normalization:** The SDK converts empty strings and `"NA"` values to `None` automatically.
|
|
875
|
+
- **Field name aliasing:** Several CDR fields use non-standard aliases in the API (e.g., `"Route list calls overage"`, `"Original Called Party UUID"`, `"Queue Type"`). The SDK handles these via Pydantic `Field(alias=...)`.
|
|
876
|
+
- **Timezone:** All CDR timestamps are in UTC. The `site_timezone` field provides the offset in minutes if you need to convert to the user's local time.
|
|
877
|
+
- **Report quota:** The 50-report limit is hard. Always delete reports after downloading to avoid hitting the cap.
|
|
878
|
+
- **Pro Pack requirement:** The Reports API (templates, create, list, download, delete) requires the Pro Pack license. The CDR Feed API does not require Pro Pack but does require the admin role to be explicitly enabled.
|
|
879
|
+
- **Async download not implemented:** The SDK's async variant of `ReportsApi.download()` raises `NotImplementedError`. Use the sync API for report downloads.
|
|
880
|
+
- **`transfer_related_call_id` contains a `local_call_id`, NOT a Correlation ID.** To link two Correlation IDs across a transfer: find CDRs where `CDR1.transfer_related_call_id = CDR2.local_call_id` — their Correlation IDs are linked. Do not compare `transfer_related_call_id` directly to `correlation_id`.
|
|
881
|
+
- **HG CDRs have both ORIGINATING and TERMINATING records.** The HuntGroup entity appears in CDRs as TERMINATING (receiving the inbound call) and ORIGINATING (dialing each agent). `Answered=true` on a HuntGroup CDR means the HG processed the call, not that a human answered. Do not count HG-typed CDRs when tallying human-answered calls.
|
|
882
|
+
- **A single call can have multiple Correlation IDs.** Attended transfers, on-prem deflections that return to cloud, and some advanced forwarding scenarios create new Correlation IDs. Use `transfer_related_call_id`/`local_call_id` linkage to reconstruct the full call path.
|
|
883
|
+
- **`related_call_id` is for deflection chaining, not just service activation.** Each HG ring attempt's ORIGINATING CDR has `related_call_id` = the HG TERMINATING CDR's `local_call_id`. This is how you link delivery attempts to the HG that distributed them. `related_call_id` is ALSO used when a new separate call is spawned by service activation (recording, exec-assistant).
|
|
884
|
+
- **On-prem correlation uses Session IDs.** When a call crosses the LGW boundary, the cloud CDR's `local_session_id`/`remote_session_id` matches the UCM CDR's Origination/Destination SIP Session ID. This is the only way to correlate cloud and on-prem (UCM) records for the same call — the Correlation ID does not appear in UCM CDRs.
|
|
885
|
+
|
|
886
|
+
---
|
|
887
|
+
|
|
888
|
+
## 9. Raw HTTP Endpoints
|
|
889
|
+
<!-- Updated by playbook session 2026-03-18 -->
|
|
890
|
+
|
|
891
|
+
All endpoints below use the `api.session.rest_*` methods from `wxc_sdk`. URLs confirmed from working CLI implementations.
|
|
892
|
+
|
|
893
|
+
```python
|
|
894
|
+
from wxc_sdk import WebexSimpleApi
|
|
895
|
+
api = WebexSimpleApi(tokens='<token>')
|
|
896
|
+
BASE = "https://webexapis.com/v1"
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
### Detailed Call History (CDR)
|
|
900
|
+
|
|
901
|
+
**Important:** The CDR endpoints use a different base URL than the standard Webex API. `startTime` and `endTime` are required and must be in ISO 8601 format (e.g., `2026-03-17T14:00:00.000Z`). The time window cannot exceed 12 hours.
|
|
902
|
+
|
|
903
|
+
#### CDR Feed (Batch/Historical)
|
|
904
|
+
|
|
905
|
+
```
|
|
906
|
+
GET https://webexapis.com/v1/cdr_feed
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
```python
|
|
910
|
+
params = {
|
|
911
|
+
"startTime": "2026-03-17T14:00:00.000Z", # ISO 8601 — required
|
|
912
|
+
"endTime": "2026-03-17T16:00:00.000Z", # ISO 8601 — required
|
|
913
|
+
# "locations": "San Jose,Austin", # optional, up to 10 comma-separated
|
|
914
|
+
"max": 1000 # no auto-pagination
|
|
915
|
+
}
|
|
916
|
+
result = api.session.rest_get(f"{BASE}/cdr_feed", params=params)
|
|
917
|
+
# Returns: {"items": [{"Start time": "...", "Answer time": "...", ...}, ...]}
|
|
918
|
+
```
|
|
919
|
+
|
|
920
|
+
#### CDR Stream (Near-Real-Time)
|
|
921
|
+
|
|
922
|
+
```
|
|
923
|
+
GET https://webexapis.com/v1/cdr_stream
|
|
924
|
+
```
|
|
925
|
+
|
|
926
|
+
```python
|
|
927
|
+
params = {
|
|
928
|
+
"startTime": "2026-03-17T14:00:00.000Z",
|
|
929
|
+
"endTime": "2026-03-17T16:00:00.000Z",
|
|
930
|
+
"max": 1000
|
|
931
|
+
}
|
|
932
|
+
result = api.session.rest_get(f"{BASE}/cdr_stream", params=params)
|
|
933
|
+
# Same response format as cdr_feed
|
|
934
|
+
```
|
|
935
|
+
|
|
936
|
+
### Report Templates
|
|
937
|
+
|
|
938
|
+
```
|
|
939
|
+
GET https://webexapis.com/v1/report/templates
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
```python
|
|
943
|
+
result = api.session.rest_get(f"{BASE}/report/templates")
|
|
944
|
+
# Returns: {"items": [{"Id": 130, "title": "Call Queue Stats", "service": "Webex Calling", ...}, ...]}
|
|
945
|
+
# Note: API returns "Id" (capital I), not "id"
|
|
946
|
+
```
|
|
947
|
+
|
|
948
|
+
### Reports
|
|
949
|
+
|
|
950
|
+
#### List Reports
|
|
951
|
+
|
|
952
|
+
```
|
|
953
|
+
GET https://webexapis.com/v1/reports
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
```python
|
|
957
|
+
params = {
|
|
958
|
+
# "reportId": "report_id",
|
|
959
|
+
# "service": "Webex Calling",
|
|
960
|
+
# "templateId": "130",
|
|
961
|
+
# "from": "2026-03-01", # from and to must be provided together
|
|
962
|
+
# "to": "2026-03-17",
|
|
963
|
+
"max": 1000
|
|
964
|
+
}
|
|
965
|
+
result = api.session.rest_get(f"{BASE}/reports", params=params)
|
|
966
|
+
```
|
|
967
|
+
|
|
968
|
+
#### Get Report Details
|
|
969
|
+
|
|
970
|
+
```
|
|
971
|
+
GET https://webexapis.com/v1/reports/{reportId}
|
|
972
|
+
```
|
|
973
|
+
|
|
974
|
+
```python
|
|
975
|
+
result = api.session.rest_get(f"{BASE}/reports/{report_id}")
|
|
976
|
+
# Returns: {"Id": "...", "title": "...", "status": "done", "downloadURL": "https://...", ...}
|
|
977
|
+
# Poll until status == "done", then use downloadURL to fetch the CSV ZIP
|
|
978
|
+
```
|
|
979
|
+
|
|
980
|
+
#### Create a Report
|
|
981
|
+
|
|
982
|
+
```
|
|
983
|
+
POST https://webexapis.com/v1/reports
|
|
984
|
+
```
|
|
985
|
+
|
|
986
|
+
```python
|
|
987
|
+
body = {
|
|
988
|
+
"templateId": 130, # from report/templates list
|
|
989
|
+
"startDate": "2026-03-01", # YYYY-MM-DD
|
|
990
|
+
"endDate": "2026-03-15" # YYYY-MM-DD
|
|
991
|
+
# "siteList": "site_url" # required only for Webex Meetings templates
|
|
992
|
+
}
|
|
993
|
+
result = api.session.rest_post(f"{BASE}/reports", json=body)
|
|
994
|
+
# Returns: {"items": {"Id": "report_id_here"}}
|
|
995
|
+
```
|
|
996
|
+
|
|
997
|
+
#### Delete a Report
|
|
998
|
+
|
|
999
|
+
```
|
|
1000
|
+
DELETE https://webexapis.com/v1/reports/{reportId}
|
|
1001
|
+
```
|
|
1002
|
+
|
|
1003
|
+
```python
|
|
1004
|
+
api.session.rest_delete(f"{BASE}/reports/{report_id}")
|
|
1005
|
+
```
|
|
1006
|
+
|
|
1007
|
+
### Converged Recordings
|
|
1008
|
+
|
|
1009
|
+
#### CLI Examples
|
|
1010
|
+
|
|
1011
|
+
```bash
|
|
1012
|
+
# List all available recordings
|
|
1013
|
+
wxcli recordings list
|
|
1014
|
+
|
|
1015
|
+
# List calling recordings in a date range
|
|
1016
|
+
wxcli recordings list \
|
|
1017
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-17T00:00:00Z" \
|
|
1018
|
+
--service-type calling
|
|
1019
|
+
|
|
1020
|
+
# List recordings filtered by status and format
|
|
1021
|
+
wxcli recordings list --status available --format MP3
|
|
1022
|
+
|
|
1023
|
+
# List recordings by location and owner type
|
|
1024
|
+
wxcli recordings list --location-id "Y2lz...bG9j" --owner-type user
|
|
1025
|
+
|
|
1026
|
+
# List recordings in JSON format with pagination
|
|
1027
|
+
wxcli recordings list --service-type calling -o json --limit 50
|
|
1028
|
+
|
|
1029
|
+
# List recordings for admin/compliance (all users in org)
|
|
1030
|
+
wxcli recordings list-converged-recordings \
|
|
1031
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-17T00:00:00Z"
|
|
1032
|
+
|
|
1033
|
+
# Get details for a specific recording
|
|
1034
|
+
wxcli recordings show "Y2lz...cmVj"
|
|
1035
|
+
|
|
1036
|
+
# Get recording metadata
|
|
1037
|
+
wxcli recordings show-metadata "Y2lz...cmVj"
|
|
1038
|
+
|
|
1039
|
+
# Delete a recording
|
|
1040
|
+
wxcli recordings delete "Y2lz...cmVj"
|
|
1041
|
+
|
|
1042
|
+
# Reassign recordings from one owner to another
|
|
1043
|
+
wxcli recordings create \
|
|
1044
|
+
--owner-email "oldowner@company.com" \
|
|
1045
|
+
--reassign-owner-email "newowner@company.com"
|
|
1046
|
+
|
|
1047
|
+
# Move recordings to recycle bin
|
|
1048
|
+
wxcli recordings create-soft-delete \
|
|
1049
|
+
--json-body '{"trashAll": true, "ownerEmail": "user@company.com"}'
|
|
1050
|
+
|
|
1051
|
+
# Restore recordings from recycle bin
|
|
1052
|
+
wxcli recordings create-restore \
|
|
1053
|
+
--json-body '{"restoreAll": true, "ownerEmail": "user@company.com"}'
|
|
1054
|
+
|
|
1055
|
+
# Purge recordings permanently from recycle bin
|
|
1056
|
+
wxcli recordings create-purge \
|
|
1057
|
+
--json-body '{"purgeAll": true, "ownerEmail": "user@company.com"}'
|
|
1058
|
+
|
|
1059
|
+
# Download a single recording's artifacts (transcript, AI notes, audio)
|
|
1060
|
+
wxcli converged-recordings download "Y2lz...cmVj"
|
|
1061
|
+
wxcli converged-recordings download "Y2lz...cmVj" --include-audio
|
|
1062
|
+
wxcli converged-recordings download "Y2lz...cmVj" -d /tmp/my-recordings
|
|
1063
|
+
|
|
1064
|
+
# Bulk export recordings to JSONL (BI-ready)
|
|
1065
|
+
wxcli converged-recordings export \
|
|
1066
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-28T00:00:00Z"
|
|
1067
|
+
|
|
1068
|
+
# Export with filters
|
|
1069
|
+
wxcli converged-recordings export \
|
|
1070
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-28T00:00:00Z" \
|
|
1071
|
+
--owner-email user@company.com --service-type calling
|
|
1072
|
+
|
|
1073
|
+
# Export as individual files per recording
|
|
1074
|
+
wxcli converged-recordings export \
|
|
1075
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-28T00:00:00Z" \
|
|
1076
|
+
--format json-per-file
|
|
1077
|
+
|
|
1078
|
+
# Export with audio files
|
|
1079
|
+
wxcli converged-recordings export \
|
|
1080
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-28T00:00:00Z" \
|
|
1081
|
+
--include-audio -d /data/recording-export
|
|
1082
|
+
```
|
|
1083
|
+
|
|
1084
|
+
#### List Recordings (User)
|
|
1085
|
+
|
|
1086
|
+
```
|
|
1087
|
+
GET https://webexapis.com/v1/convergedRecordings
|
|
1088
|
+
```
|
|
1089
|
+
|
|
1090
|
+
```python
|
|
1091
|
+
params = {
|
|
1092
|
+
# "from": "2026-03-01T00:00:00Z",
|
|
1093
|
+
# "to": "2026-03-17T00:00:00Z",
|
|
1094
|
+
# "status": "available",
|
|
1095
|
+
# "serviceType": "calling",
|
|
1096
|
+
# "format": "MP3",
|
|
1097
|
+
# "ownerType": "user",
|
|
1098
|
+
# "storageRegion": "US",
|
|
1099
|
+
# "locationId": "location_id",
|
|
1100
|
+
# "topic": "search_term",
|
|
1101
|
+
"max": 1000
|
|
1102
|
+
}
|
|
1103
|
+
result = api.session.rest_get(f"{BASE}/convergedRecordings", params=params)
|
|
1104
|
+
```
|
|
1105
|
+
|
|
1106
|
+
#### List Recordings (Admin/Compliance)
|
|
1107
|
+
|
|
1108
|
+
```
|
|
1109
|
+
GET https://webexapis.com/v1/admin/convergedRecordings
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
```python
|
|
1113
|
+
params = {
|
|
1114
|
+
# "ownerId": "user_id",
|
|
1115
|
+
# "ownerEmail": "user@company.com",
|
|
1116
|
+
# All same params as user endpoint above
|
|
1117
|
+
"max": 1000
|
|
1118
|
+
}
|
|
1119
|
+
result = api.session.rest_get(f"{BASE}/admin/convergedRecordings", params=params)
|
|
1120
|
+
```
|
|
1121
|
+
|
|
1122
|
+
#### Get Recording Details
|
|
1123
|
+
|
|
1124
|
+
```
|
|
1125
|
+
GET https://webexapis.com/v1/convergedRecordings/{recordingId}
|
|
1126
|
+
```
|
|
1127
|
+
|
|
1128
|
+
```python
|
|
1129
|
+
result = api.session.rest_get(f"{BASE}/convergedRecordings/{recording_id}")
|
|
1130
|
+
```
|
|
1131
|
+
|
|
1132
|
+
#### Delete a Recording
|
|
1133
|
+
|
|
1134
|
+
```
|
|
1135
|
+
DELETE https://webexapis.com/v1/convergedRecordings/{recordingId}
|
|
1136
|
+
```
|
|
1137
|
+
|
|
1138
|
+
```python
|
|
1139
|
+
api.session.rest_delete(f"{BASE}/convergedRecordings/{recording_id}")
|
|
1140
|
+
```
|
|
1141
|
+
|
|
1142
|
+
#### Get Recording Metadata
|
|
1143
|
+
|
|
1144
|
+
```
|
|
1145
|
+
GET https://webexapis.com/v1/convergedRecordings/{recordingId}/metadata
|
|
1146
|
+
```
|
|
1147
|
+
|
|
1148
|
+
```python
|
|
1149
|
+
params = {"showAllTypes": "true"} # optional — show all attribute types
|
|
1150
|
+
result = api.session.rest_get(f"{BASE}/convergedRecordings/{recording_id}/metadata", params=params)
|
|
1151
|
+
```
|
|
1152
|
+
|
|
1153
|
+
#### Reassign Recordings
|
|
1154
|
+
|
|
1155
|
+
```
|
|
1156
|
+
POST https://webexapis.com/v1/convergedRecordings/reassign
|
|
1157
|
+
```
|
|
1158
|
+
|
|
1159
|
+
```python
|
|
1160
|
+
body = {
|
|
1161
|
+
"reassignOwnerEmail": "newowner@company.com",
|
|
1162
|
+
"ownerEmail": "oldowner@company.com"
|
|
1163
|
+
# or "ownerID": "user_id"
|
|
1164
|
+
}
|
|
1165
|
+
result = api.session.rest_post(f"{BASE}/convergedRecordings/reassign", json=body)
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
#### Move Recordings to Recycle Bin
|
|
1169
|
+
|
|
1170
|
+
```
|
|
1171
|
+
POST https://webexapis.com/v1/convergedRecordings/softDelete
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1174
|
+
```python
|
|
1175
|
+
body = {
|
|
1176
|
+
"trashAll": True,
|
|
1177
|
+
"ownerEmail": "user@company.com"
|
|
1178
|
+
}
|
|
1179
|
+
result = api.session.rest_post(f"{BASE}/convergedRecordings/softDelete", json=body)
|
|
1180
|
+
```
|
|
1181
|
+
|
|
1182
|
+
#### Restore Recordings from Recycle Bin
|
|
1183
|
+
|
|
1184
|
+
```
|
|
1185
|
+
POST https://webexapis.com/v1/convergedRecordings/restore
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
```python
|
|
1189
|
+
body = {
|
|
1190
|
+
"restoreAll": True,
|
|
1191
|
+
"ownerEmail": "user@company.com"
|
|
1192
|
+
}
|
|
1193
|
+
result = api.session.rest_post(f"{BASE}/convergedRecordings/restore", json=body)
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1196
|
+
#### Download Recording Artifacts
|
|
1197
|
+
|
|
1198
|
+
Downloads a single recording's transcript, AI-generated notes, and optionally the MP3 audio file to a local directory. Uses the `temporaryDirectDownloadLinks` from the recording detail response. The download URLs are pre-signed — they are fetched directly with HTTP GET, no Bearer token needed.
|
|
1199
|
+
|
|
1200
|
+
```bash
|
|
1201
|
+
wxcli converged-recordings download RECORDING_ID [--include-audio] [-d OUTPUT_DIR]
|
|
1202
|
+
```
|
|
1203
|
+
|
|
1204
|
+
Output structure:
|
|
1205
|
+
```
|
|
1206
|
+
{output_dir}/{recording_id}/
|
|
1207
|
+
metadata.json # full recording detail response
|
|
1208
|
+
transcript.txt # if available
|
|
1209
|
+
suggested_notes.html # if available
|
|
1210
|
+
short_notes.html # if available
|
|
1211
|
+
action_items.html # if available
|
|
1212
|
+
audio.mp3 # if --include-audio and available
|
|
1213
|
+
```
|
|
1214
|
+
|
|
1215
|
+
#### Bulk Export Recordings
|
|
1216
|
+
|
|
1217
|
+
Paginates the admin listing endpoint, fetches detail for each recording, and downloads all text/AI artifacts. Produces either a single JSONL file (BI-ready) or one directory per recording.
|
|
1218
|
+
|
|
1219
|
+
```bash
|
|
1220
|
+
wxcli converged-recordings export --from START --to END [filters...] [--format jsonl|json-per-file]
|
|
1221
|
+
```
|
|
1222
|
+
|
|
1223
|
+
JSONL mode (default): writes `recordings.jsonl` with one JSON object per line containing all metadata and inline text content. Audio files (if `--include-audio`) go to `{output_dir}/audio/{recording_id}.mp3`.
|
|
1224
|
+
|
|
1225
|
+
JSON-per-file mode: same directory structure as the `download` command, one directory per recording.
|
|
1226
|
+
|
|
1227
|
+
Processing is sequential — each recording is fully fetched and downloaded before moving to the next, since download links expire in 3 hours.
|
|
1228
|
+
|
|
1229
|
+
#### Purge Recordings from Recycle Bin
|
|
1230
|
+
|
|
1231
|
+
```
|
|
1232
|
+
POST https://webexapis.com/v1/convergedRecordings/purge
|
|
1233
|
+
```
|
|
1234
|
+
|
|
1235
|
+
```python
|
|
1236
|
+
body = {
|
|
1237
|
+
"purgeAll": True,
|
|
1238
|
+
"ownerEmail": "user@company.com"
|
|
1239
|
+
}
|
|
1240
|
+
result = api.session.rest_post(f"{BASE}/convergedRecordings/purge", json=body)
|
|
1241
|
+
```
|
|
1242
|
+
|
|
1243
|
+
### Recording Reports
|
|
1244
|
+
|
|
1245
|
+
#### CLI Examples
|
|
1246
|
+
|
|
1247
|
+
```bash
|
|
1248
|
+
# List recording audit report summaries
|
|
1249
|
+
wxcli recording-report list \
|
|
1250
|
+
--from "2026-03-01T00:00:00Z" --to "2026-03-17T00:00:00Z"
|
|
1251
|
+
|
|
1252
|
+
# List recording audit summaries for a specific host
|
|
1253
|
+
wxcli recording-report list --host-email "host@company.com"
|
|
1254
|
+
|
|
1255
|
+
# Get recording audit report access details
|
|
1256
|
+
wxcli recording-report list-access-detail --recording-id "Y2lz...cmVj"
|
|
1257
|
+
|
|
1258
|
+
# List meeting archive summaries
|
|
1259
|
+
wxcli recording-report list-meeting-archive-summaries
|
|
1260
|
+
|
|
1261
|
+
# Get meeting archive details
|
|
1262
|
+
wxcli recording-report show "Y2lz...YXJj"
|
|
1263
|
+
```
|
|
1264
|
+
|
|
1265
|
+
#### Access Summary
|
|
1266
|
+
|
|
1267
|
+
```
|
|
1268
|
+
GET https://webexapis.com/v1/recordingReport/accessSummary
|
|
1269
|
+
```
|
|
1270
|
+
|
|
1271
|
+
```python
|
|
1272
|
+
params = {
|
|
1273
|
+
# "recordingId": "recording_id",
|
|
1274
|
+
"max": 1000
|
|
1275
|
+
}
|
|
1276
|
+
result = api.session.rest_get(f"{BASE}/recordingReport/accessSummary", params=params)
|
|
1277
|
+
```
|
|
1278
|
+
|
|
1279
|
+
#### Access Detail
|
|
1280
|
+
|
|
1281
|
+
```
|
|
1282
|
+
GET https://webexapis.com/v1/recordingReport/accessDetail
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
```python
|
|
1286
|
+
params = {
|
|
1287
|
+
# "recordingId": "recording_id",
|
|
1288
|
+
"max": 1000
|
|
1289
|
+
}
|
|
1290
|
+
result = api.session.rest_get(f"{BASE}/recordingReport/accessDetail", params=params)
|
|
1291
|
+
```
|
|
1292
|
+
|
|
1293
|
+
#### Meeting Archive Summaries
|
|
1294
|
+
|
|
1295
|
+
```
|
|
1296
|
+
GET https://webexapis.com/v1/recordingReport/meetingArchiveSummaries
|
|
1297
|
+
```
|
|
1298
|
+
|
|
1299
|
+
```python
|
|
1300
|
+
result = api.session.rest_get(f"{BASE}/recordingReport/meetingArchiveSummaries", params={"max": 1000})
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
#### Meeting Archive Detail
|
|
1304
|
+
|
|
1305
|
+
```
|
|
1306
|
+
GET https://webexapis.com/v1/recordingReport/meetingArchives/{archiveId}
|
|
1307
|
+
```
|
|
1308
|
+
|
|
1309
|
+
```python
|
|
1310
|
+
result = api.session.rest_get(f"{BASE}/recordingReport/meetingArchives/{archive_id}")
|
|
1311
|
+
```
|
|
1312
|
+
|
|
1313
|
+
---
|
|
1314
|
+
|
|
1315
|
+
## See Also
|
|
1316
|
+
|
|
1317
|
+
- **[authentication.md](authentication.md)** — OAuth scopes and token management. CDR access requires `spark-admin:calling_cdr_read` with an explicit admin role; Reports API requires `analytics:read_all` with Pro Pack.
|
|
1318
|
+
- **[call-features-major.md](call-features-major.md)** — Call Queue and Auto Attendant configuration. CDR fields like `queue_type`, `auto_attendant_key_pressed`, and queue-related report templates correspond to features configured there.
|