wxcli 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (413) hide show
  1. wxcli/__init__.py +4 -0
  2. wxcli/_playbook/.claude/agents/migration-advisor.md +239 -0
  3. wxcli/_playbook/.claude/agents/wxc-calling-builder.md +946 -0
  4. wxcli/_playbook/.claude/rules/cleanup.md +29 -0
  5. wxcli/_playbook/.claude/rules/cucm-migration.md +58 -0
  6. wxcli/_playbook/.claude/rules/org-health.md +14 -0
  7. wxcli/_playbook/.claude/settings.json +8 -0
  8. wxcli/_playbook/.claude/skills/audit-compliance/SKILL.md +515 -0
  9. wxcli/_playbook/.claude/skills/call-control/SKILL.md +747 -0
  10. wxcli/_playbook/.claude/skills/configure-features/SKILL.md +623 -0
  11. wxcli/_playbook/.claude/skills/configure-routing/SKILL.md +627 -0
  12. wxcli/_playbook/.claude/skills/contact-center/SKILL.md +1181 -0
  13. wxcli/_playbook/.claude/skills/cucm-migrate/SKILL.md +820 -0
  14. wxcli/_playbook/.claude/skills/customer-assist/SKILL.md +443 -0
  15. wxcli/_playbook/.claude/skills/device-platform/SKILL.md +407 -0
  16. wxcli/_playbook/.claude/skills/manage-call-settings/SKILL.md +757 -0
  17. wxcli/_playbook/.claude/skills/manage-devices/SKILL.md +790 -0
  18. wxcli/_playbook/.claude/skills/manage-identity/SKILL.md +638 -0
  19. wxcli/_playbook/.claude/skills/manage-licensing/SKILL.md +528 -0
  20. wxcli/_playbook/.claude/skills/manage-meetings/SKILL.md +708 -0
  21. wxcli/_playbook/.claude/skills/messaging-bots/SKILL.md +365 -0
  22. wxcli/_playbook/.claude/skills/messaging-spaces/SKILL.md +520 -0
  23. wxcli/_playbook/.claude/skills/org-health/SKILL.md +159 -0
  24. wxcli/_playbook/.claude/skills/provision-calling/SKILL.md +421 -0
  25. wxcli/_playbook/.claude/skills/query-live/SKILL.md +183 -0
  26. wxcli/_playbook/.claude/skills/query-live/domains/call-flow-trace.md +223 -0
  27. wxcli/_playbook/.claude/skills/query-live/domains/call-history.md +44 -0
  28. wxcli/_playbook/.claude/skills/query-live/domains/features.md +169 -0
  29. wxcli/_playbook/.claude/skills/query-live/domains/numbers.md +93 -0
  30. wxcli/_playbook/.claude/skills/query-live/domains/people-and-settings.md +146 -0
  31. wxcli/_playbook/.claude/skills/query-live/domains/routing.md +124 -0
  32. wxcli/_playbook/.claude/skills/reporting/SKILL.md +501 -0
  33. wxcli/_playbook/.claude/skills/reporting/references/cdr-recipes.md +1628 -0
  34. wxcli/_playbook/.claude/skills/reporting-cc/SKILL.md +251 -0
  35. wxcli/_playbook/.claude/skills/reporting-meetings/SKILL.md +290 -0
  36. wxcli/_playbook/.claude/skills/teardown/SKILL.md +214 -0
  37. wxcli/_playbook/.claude/skills/video-mesh/SKILL.md +379 -0
  38. wxcli/_playbook/.claude/skills/wxc-calling-debug/SKILL.md +475 -0
  39. wxcli/_playbook/CLAUDE.md +373 -0
  40. wxcli/_playbook/docs/reference/CLAUDE.md +25 -0
  41. wxcli/_playbook/docs/reference/admin-apps-data.md +643 -0
  42. wxcli/_playbook/docs/reference/admin-audit-security.md +322 -0
  43. wxcli/_playbook/docs/reference/admin-hybrid.md +383 -0
  44. wxcli/_playbook/docs/reference/admin-identity-scim.md +1007 -0
  45. wxcli/_playbook/docs/reference/admin-licensing.md +414 -0
  46. wxcli/_playbook/docs/reference/admin-org-management.md +586 -0
  47. wxcli/_playbook/docs/reference/admin-partner.md +357 -0
  48. wxcli/_playbook/docs/reference/archive/wxc-sdk-patterns.md +1229 -0
  49. wxcli/_playbook/docs/reference/archive/wxcadm-advanced.md +835 -0
  50. wxcli/_playbook/docs/reference/archive/wxcadm-core.md +743 -0
  51. wxcli/_playbook/docs/reference/archive/wxcadm-devices-workspaces.md +1305 -0
  52. wxcli/_playbook/docs/reference/archive/wxcadm-features.md +849 -0
  53. wxcli/_playbook/docs/reference/archive/wxcadm-locations.md +938 -0
  54. wxcli/_playbook/docs/reference/archive/wxcadm-person.md +1255 -0
  55. wxcli/_playbook/docs/reference/archive/wxcadm-routing.md +1262 -0
  56. wxcli/_playbook/docs/reference/authentication.md +965 -0
  57. wxcli/_playbook/docs/reference/call-control.md +1205 -0
  58. wxcli/_playbook/docs/reference/call-features-additional.md +2541 -0
  59. wxcli/_playbook/docs/reference/call-features-major.md +1320 -0
  60. wxcli/_playbook/docs/reference/call-routing.md +2304 -0
  61. wxcli/_playbook/docs/reference/contact-center-analytics.md +1049 -0
  62. wxcli/_playbook/docs/reference/contact-center-core.md +1614 -0
  63. wxcli/_playbook/docs/reference/contact-center-journey.md +457 -0
  64. wxcli/_playbook/docs/reference/contact-center-routing.md +1138 -0
  65. wxcli/_playbook/docs/reference/devices-core.md +1869 -0
  66. wxcli/_playbook/docs/reference/devices-dect.md +1150 -0
  67. wxcli/_playbook/docs/reference/devices-platform.md +467 -0
  68. wxcli/_playbook/docs/reference/devices-workspaces.md +1426 -0
  69. wxcli/_playbook/docs/reference/emergency-services.md +1122 -0
  70. wxcli/_playbook/docs/reference/location-calling-core.md +2037 -0
  71. wxcli/_playbook/docs/reference/location-calling-media.md +1334 -0
  72. wxcli/_playbook/docs/reference/location-recording-advanced.md +1482 -0
  73. wxcli/_playbook/docs/reference/meetings-content.md +473 -0
  74. wxcli/_playbook/docs/reference/meetings-core.md +903 -0
  75. wxcli/_playbook/docs/reference/meetings-infrastructure.md +899 -0
  76. wxcli/_playbook/docs/reference/meetings-settings.md +850 -0
  77. wxcli/_playbook/docs/reference/messaging-bots.md +1091 -0
  78. wxcli/_playbook/docs/reference/messaging-spaces.md +695 -0
  79. wxcli/_playbook/docs/reference/person-call-settings-behavior.md +1639 -0
  80. wxcli/_playbook/docs/reference/person-call-settings-handling.md +1394 -0
  81. wxcli/_playbook/docs/reference/person-call-settings-media.md +1898 -0
  82. wxcli/_playbook/docs/reference/person-call-settings-permissions.md +1329 -0
  83. wxcli/_playbook/docs/reference/provisioning.md +1366 -0
  84. wxcli/_playbook/docs/reference/reporting-analytics.md +1318 -0
  85. wxcli/_playbook/docs/reference/self-service-call-settings.md +1020 -0
  86. wxcli/_playbook/docs/reference/virtual-lines.md +1132 -0
  87. wxcli/_playbook/docs/reference/webhooks-events.md +1444 -0
  88. wxcli/_playbook/docs/reference/wxcadm-xsi-realtime.md +953 -0
  89. wxcli/_version.py +24 -0
  90. wxcli/auth.py +137 -0
  91. wxcli/commands/__init__.py +0 -0
  92. wxcli/commands/_registry.py +181 -0
  93. wxcli/commands/activation_email.py +103 -0
  94. wxcli/commands/admin_recordings.py +585 -0
  95. wxcli/commands/analytics.py +105 -0
  96. wxcli/commands/announcement_playlists.py +219 -0
  97. wxcli/commands/announcements.py +519 -0
  98. wxcli/commands/archive_users.py +36 -0
  99. wxcli/commands/attachment_actions.py +60 -0
  100. wxcli/commands/audit_events.py +83 -0
  101. wxcli/commands/authorizations.py +113 -0
  102. wxcli/commands/auto_attendant.py +642 -0
  103. wxcli/commands/broadworks_billing_reports.py +126 -0
  104. wxcli/commands/broadworks_enterprises.py +160 -0
  105. wxcli/commands/broadworks_subscribers.py +319 -0
  106. wxcli/commands/broadworks_workspaces.py +108 -0
  107. wxcli/commands/call_controls.py +1304 -0
  108. wxcli/commands/call_park.py +494 -0
  109. wxcli/commands/call_pickup.py +229 -0
  110. wxcli/commands/call_queue.py +1878 -0
  111. wxcli/commands/call_recording.py +707 -0
  112. wxcli/commands/call_routing.py +1610 -0
  113. wxcli/commands/call_settings_for_me_phase_5.py +212 -0
  114. wxcli/commands/caller_reputation.py +169 -0
  115. wxcli/commands/calling_service.py +305 -0
  116. wxcli/commands/cc_address_book.py +770 -0
  117. wxcli/commands/cc_agent_greetings.py +242 -0
  118. wxcli/commands/cc_agent_summaries.py +39 -0
  119. wxcli/commands/cc_agent_wellbeing.py +216 -0
  120. wxcli/commands/cc_agents.py +425 -0
  121. wxcli/commands/cc_ai_assistant.py +55 -0
  122. wxcli/commands/cc_ai_feature.py +294 -0
  123. wxcli/commands/cc_audio_files.py +149 -0
  124. wxcli/commands/cc_auto_csat.py +311 -0
  125. wxcli/commands/cc_aux_code.py +458 -0
  126. wxcli/commands/cc_business_hour.py +353 -0
  127. wxcli/commands/cc_call_monitoring.py +228 -0
  128. wxcli/commands/cc_callbacks.py +194 -0
  129. wxcli/commands/cc_campaign.py +212 -0
  130. wxcli/commands/cc_captures.py +39 -0
  131. wxcli/commands/cc_contact_list.py +169 -0
  132. wxcli/commands/cc_contact_number.py +295 -0
  133. wxcli/commands/cc_data_sources.py +235 -0
  134. wxcli/commands/cc_desktop_layout.py +380 -0
  135. wxcli/commands/cc_desktop_profile.py +322 -0
  136. wxcli/commands/cc_dial_number.py +511 -0
  137. wxcli/commands/cc_dial_plan.py +347 -0
  138. wxcli/commands/cc_dnc.py +101 -0
  139. wxcli/commands/cc_entry_point.py +545 -0
  140. wxcli/commands/cc_ewt.py +51 -0
  141. wxcli/commands/cc_flow.py +477 -0
  142. wxcli/commands/cc_global_vars.py +430 -0
  143. wxcli/commands/cc_holiday_list.py +335 -0
  144. wxcli/commands/cc_journey.py +1261 -0
  145. wxcli/commands/cc_legacy_flows.py +49 -0
  146. wxcli/commands/cc_multimedia_profile.py +436 -0
  147. wxcli/commands/cc_notification.py +51 -0
  148. wxcli/commands/cc_outdial_ani.py +604 -0
  149. wxcli/commands/cc_overrides.py +341 -0
  150. wxcli/commands/cc_queue.py +1083 -0
  151. wxcli/commands/cc_queue_stats.py +55 -0
  152. wxcli/commands/cc_realtime.py +51 -0
  153. wxcli/commands/cc_resource_collection.py +312 -0
  154. wxcli/commands/cc_search.py +46 -0
  155. wxcli/commands/cc_site.py +400 -0
  156. wxcli/commands/cc_skill.py +350 -0
  157. wxcli/commands/cc_skill_profile.py +289 -0
  158. wxcli/commands/cc_subscriptions.py +426 -0
  159. wxcli/commands/cc_summaries.py +130 -0
  160. wxcli/commands/cc_tasks.py +844 -0
  161. wxcli/commands/cc_team.py +325 -0
  162. wxcli/commands/cc_user_profiles.py +349 -0
  163. wxcli/commands/cc_users.py +701 -0
  164. wxcli/commands/cc_work_types.py +363 -0
  165. wxcli/commands/cdr.py +89 -0
  166. wxcli/commands/classifications.py +38 -0
  167. wxcli/commands/cleanup.py +1427 -0
  168. wxcli/commands/client_settings.py +72 -0
  169. wxcli/commands/conference.py +328 -0
  170. wxcli/commands/configure.py +72 -0
  171. wxcli/commands/converged_recordings.py +347 -0
  172. wxcli/commands/converged_recordings_export.py +310 -0
  173. wxcli/commands/cq_playlists.py +42 -0
  174. wxcli/commands/cucm.py +2794 -0
  175. wxcli/commands/cucm_config.py +129 -0
  176. wxcli/commands/customer_assist.py +373 -0
  177. wxcli/commands/data_sources.py +227 -0
  178. wxcli/commands/dect_devices.py +787 -0
  179. wxcli/commands/device_configurations.py +77 -0
  180. wxcli/commands/device_dynamic_settings.py +320 -0
  181. wxcli/commands/device_settings.py +1489 -0
  182. wxcli/commands/devices.py +280 -0
  183. wxcli/commands/domains.py +142 -0
  184. wxcli/commands/ecm.py +178 -0
  185. wxcli/commands/emergency_services.py +827 -0
  186. wxcli/commands/events.py +83 -0
  187. wxcli/commands/external_voicemail.py +52 -0
  188. wxcli/commands/groups.py +206 -0
  189. wxcli/commands/guest_management.py +76 -0
  190. wxcli/commands/hds.py +340 -0
  191. wxcli/commands/hot_desk.py +67 -0
  192. wxcli/commands/hot_desking_members.py +118 -0
  193. wxcli/commands/hot_desking_portal.py +124 -0
  194. wxcli/commands/hunt_group.py +577 -0
  195. wxcli/commands/hybrid_clusters.py +71 -0
  196. wxcli/commands/hybrid_connectors.py +67 -0
  197. wxcli/commands/identity_org.py +159 -0
  198. wxcli/commands/init_playbook.py +155 -0
  199. wxcli/commands/licenses.py +106 -0
  200. wxcli/commands/live_monitoring.py +40 -0
  201. wxcli/commands/location_call_handling.py +577 -0
  202. wxcli/commands/location_schedules.py +341 -0
  203. wxcli/commands/location_settings.py +1297 -0
  204. wxcli/commands/location_voicemail.py +494 -0
  205. wxcli/commands/locations.py +336 -0
  206. wxcli/commands/meeting_captions.py +110 -0
  207. wxcli/commands/meeting_chats.py +63 -0
  208. wxcli/commands/meeting_invitees.py +234 -0
  209. wxcli/commands/meeting_messages.py +28 -0
  210. wxcli/commands/meeting_participants.py +278 -0
  211. wxcli/commands/meeting_polls.py +111 -0
  212. wxcli/commands/meeting_preferences.py +515 -0
  213. wxcli/commands/meeting_qa.py +78 -0
  214. wxcli/commands/meeting_qualities.py +43 -0
  215. wxcli/commands/meeting_reports.py +101 -0
  216. wxcli/commands/meeting_session_types.py +105 -0
  217. wxcli/commands/meeting_site.py +57 -0
  218. wxcli/commands/meeting_slido.py +44 -0
  219. wxcli/commands/meeting_summaries.py +92 -0
  220. wxcli/commands/meeting_tracking_codes.py +233 -0
  221. wxcli/commands/meeting_transcripts.py +230 -0
  222. wxcli/commands/meetings.py +1997 -0
  223. wxcli/commands/memberships.py +164 -0
  224. wxcli/commands/messages.py +213 -0
  225. wxcli/commands/mode_management.py +244 -0
  226. wxcli/commands/my_call_settings.py +3577 -0
  227. wxcli/commands/numbers.py +405 -0
  228. wxcli/commands/operating_modes.py +410 -0
  229. wxcli/commands/org_contacts.py +284 -0
  230. wxcli/commands/org_health_cli.py +55 -0
  231. wxcli/commands/org_settings.py +71 -0
  232. wxcli/commands/organizations.py +83 -0
  233. wxcli/commands/paging_group.py +257 -0
  234. wxcli/commands/partner_admins.py +141 -0
  235. wxcli/commands/partner_reports.py +188 -0
  236. wxcli/commands/partner_tags.py +216 -0
  237. wxcli/commands/people.py +279 -0
  238. wxcli/commands/person_call_settings.py +71 -0
  239. wxcli/commands/pstn.py +280 -0
  240. wxcli/commands/recording_report.py +154 -0
  241. wxcli/commands/report_templates.py +38 -0
  242. wxcli/commands/reports.py +144 -0
  243. wxcli/commands/resource_group_memberships.py +160 -0
  244. wxcli/commands/resource_groups.py +67 -0
  245. wxcli/commands/roles.py +63 -0
  246. wxcli/commands/room_tabs.py +160 -0
  247. wxcli/commands/rooms.py +225 -0
  248. wxcli/commands/scim_bulk.py +46 -0
  249. wxcli/commands/scim_groups.py +246 -0
  250. wxcli/commands/scim_schemas.py +82 -0
  251. wxcli/commands/scim_users.py +283 -0
  252. wxcli/commands/security_audit.py +54 -0
  253. wxcli/commands/service_apps.py +51 -0
  254. wxcli/commands/single_number_reach.py +209 -0
  255. wxcli/commands/team_memberships.py +155 -0
  256. wxcli/commands/teams.py +153 -0
  257. wxcli/commands/ucm_profile.py +42 -0
  258. wxcli/commands/update.py +219 -0
  259. wxcli/commands/user_settings.py +5116 -0
  260. wxcli/commands/video_mesh.py +1090 -0
  261. wxcli/commands/virtual_extensions.py +502 -0
  262. wxcli/commands/virtual_line_settings.py +2072 -0
  263. wxcli/commands/webhooks.py +176 -0
  264. wxcli/commands/wholesale_billing_reports.py +147 -0
  265. wxcli/commands/wholesale_provisioning.py +523 -0
  266. wxcli/commands/workspace_locations.py +339 -0
  267. wxcli/commands/workspace_metrics.py +103 -0
  268. wxcli/commands/workspace_personalization.py +70 -0
  269. wxcli/commands/workspace_settings.py +3347 -0
  270. wxcli/commands/workspaces.py +279 -0
  271. wxcli/commands/xapi.py +114 -0
  272. wxcli/config.py +139 -0
  273. wxcli/errors.py +77 -0
  274. wxcli/main.py +210 -0
  275. wxcli/migration/CLAUDE.md +106 -0
  276. wxcli/migration/__init__.py +1 -0
  277. wxcli/migration/advisory/CLAUDE.md +196 -0
  278. wxcli/migration/advisory/__init__.py +46 -0
  279. wxcli/migration/advisory/advisor.py +107 -0
  280. wxcli/migration/advisory/advisory_patterns.py +2552 -0
  281. wxcli/migration/advisory/recommendation_rules.py +835 -0
  282. wxcli/migration/cucm/CLAUDE.md +74 -0
  283. wxcli/migration/cucm/__init__.py +5 -0
  284. wxcli/migration/cucm/connection.py +265 -0
  285. wxcli/migration/cucm/discovery.py +225 -0
  286. wxcli/migration/cucm/extractors/__init__.py +1 -0
  287. wxcli/migration/cucm/extractors/announcements.py +92 -0
  288. wxcli/migration/cucm/extractors/base.py +90 -0
  289. wxcli/migration/cucm/extractors/device_profiles.py +98 -0
  290. wxcli/migration/cucm/extractors/devices.py +193 -0
  291. wxcli/migration/cucm/extractors/e911.py +103 -0
  292. wxcli/migration/cucm/extractors/features.py +309 -0
  293. wxcli/migration/cucm/extractors/helpers.py +73 -0
  294. wxcli/migration/cucm/extractors/informational.py +295 -0
  295. wxcli/migration/cucm/extractors/locations.py +221 -0
  296. wxcli/migration/cucm/extractors/moh.py +100 -0
  297. wxcli/migration/cucm/extractors/remote_destinations.py +96 -0
  298. wxcli/migration/cucm/extractors/routing.py +493 -0
  299. wxcli/migration/cucm/extractors/shared_lines.py +146 -0
  300. wxcli/migration/cucm/extractors/templates.py +229 -0
  301. wxcli/migration/cucm/extractors/tier4.py +173 -0
  302. wxcli/migration/cucm/extractors/users.py +240 -0
  303. wxcli/migration/cucm/extractors/voicemail.py +243 -0
  304. wxcli/migration/cucm/extractors/workspaces.py +88 -0
  305. wxcli/migration/cucm/unity_connection.py +304 -0
  306. wxcli/migration/execute/CLAUDE.md +372 -0
  307. wxcli/migration/execute/__init__.py +303 -0
  308. wxcli/migration/execute/batch.py +277 -0
  309. wxcli/migration/execute/dependency.py +483 -0
  310. wxcli/migration/execute/engine.py +964 -0
  311. wxcli/migration/execute/handlers.py +2232 -0
  312. wxcli/migration/execute/planner.py +1939 -0
  313. wxcli/migration/execute/runtime.py +571 -0
  314. wxcli/migration/export/CLAUDE.md +49 -0
  315. wxcli/migration/export/__init__.py +8 -0
  316. wxcli/migration/export/csv_export.py +126 -0
  317. wxcli/migration/export/deployment_plan.py +479 -0
  318. wxcli/migration/export/json_export.py +60 -0
  319. wxcli/migration/models.py +941 -0
  320. wxcli/migration/phone_models.py +50 -0
  321. wxcli/migration/preflight/CLAUDE.md +52 -0
  322. wxcli/migration/preflight/__init__.py +89 -0
  323. wxcli/migration/preflight/checks.py +911 -0
  324. wxcli/migration/preflight/runner.py +293 -0
  325. wxcli/migration/rate_limiter.py +144 -0
  326. wxcli/migration/report/CLAUDE.md +245 -0
  327. wxcli/migration/report/__init__.py +7 -0
  328. wxcli/migration/report/appendix.py +2437 -0
  329. wxcli/migration/report/assembler.py +183 -0
  330. wxcli/migration/report/charts.py +263 -0
  331. wxcli/migration/report/executive.py +776 -0
  332. wxcli/migration/report/explainer.py +704 -0
  333. wxcli/migration/report/helpers.py +74 -0
  334. wxcli/migration/report/ingest.py +152 -0
  335. wxcli/migration/report/notice_templates.py +192 -0
  336. wxcli/migration/report/score.py +375 -0
  337. wxcli/migration/report/styles.py +1052 -0
  338. wxcli/migration/report/user_diff.py +1052 -0
  339. wxcli/migration/report/user_notice.py +425 -0
  340. wxcli/migration/state.py +139 -0
  341. wxcli/migration/store.py +860 -0
  342. wxcli/migration/transform/CLAUDE.md +107 -0
  343. wxcli/migration/transform/__init__.py +12 -0
  344. wxcli/migration/transform/analysis_pipeline.py +453 -0
  345. wxcli/migration/transform/analyzers/__init__.py +142 -0
  346. wxcli/migration/transform/analyzers/css_permission.py +189 -0
  347. wxcli/migration/transform/analyzers/css_routing.py +335 -0
  348. wxcli/migration/transform/analyzers/device_compatibility.py +122 -0
  349. wxcli/migration/transform/analyzers/dn_ambiguity.py +131 -0
  350. wxcli/migration/transform/analyzers/duplicate_user.py +221 -0
  351. wxcli/migration/transform/analyzers/extension_conflict.py +173 -0
  352. wxcli/migration/transform/analyzers/feature_approximation.py +227 -0
  353. wxcli/migration/transform/analyzers/layout_overflow.py +174 -0
  354. wxcli/migration/transform/analyzers/location_ambiguity.py +184 -0
  355. wxcli/migration/transform/analyzers/missing_data.py +300 -0
  356. wxcli/migration/transform/analyzers/selective_call_handling.py +394 -0
  357. wxcli/migration/transform/analyzers/shared_line.py +170 -0
  358. wxcli/migration/transform/analyzers/voicemail_compatibility.py +267 -0
  359. wxcli/migration/transform/analyzers/workspace_license.py +212 -0
  360. wxcli/migration/transform/cross_reference.py +1136 -0
  361. wxcli/migration/transform/cucm_pattern.py +246 -0
  362. wxcli/migration/transform/decisions.py +301 -0
  363. wxcli/migration/transform/e164.py +145 -0
  364. wxcli/migration/transform/engine.py +256 -0
  365. wxcli/migration/transform/mappers/CLAUDE.md +123 -0
  366. wxcli/migration/transform/mappers/__init__.py +76 -0
  367. wxcli/migration/transform/mappers/announcement_mapper.py +122 -0
  368. wxcli/migration/transform/mappers/base.py +190 -0
  369. wxcli/migration/transform/mappers/button_template_mapper.py +186 -0
  370. wxcli/migration/transform/mappers/call_forwarding_mapper.py +228 -0
  371. wxcli/migration/transform/mappers/call_settings_mapper.py +144 -0
  372. wxcli/migration/transform/mappers/css_mapper.py +868 -0
  373. wxcli/migration/transform/mappers/dect_mapper.py +367 -0
  374. wxcli/migration/transform/mappers/device_layout_mapper.py +289 -0
  375. wxcli/migration/transform/mappers/device_mapper.py +227 -0
  376. wxcli/migration/transform/mappers/device_profile_mapper.py +190 -0
  377. wxcli/migration/transform/mappers/device_settings_mapper.py +464 -0
  378. wxcli/migration/transform/mappers/e911_mapper.py +129 -0
  379. wxcli/migration/transform/mappers/ecbn_mapper.py +263 -0
  380. wxcli/migration/transform/mappers/executive_assistant_mapper.py +156 -0
  381. wxcli/migration/transform/mappers/feature_mapper.py +1179 -0
  382. wxcli/migration/transform/mappers/line_mapper.py +310 -0
  383. wxcli/migration/transform/mappers/location_mapper.py +235 -0
  384. wxcli/migration/transform/mappers/moh_mapper.py +114 -0
  385. wxcli/migration/transform/mappers/monitoring_mapper.py +221 -0
  386. wxcli/migration/transform/mappers/receptionist_mapper.py +245 -0
  387. wxcli/migration/transform/mappers/routing_mapper.py +821 -0
  388. wxcli/migration/transform/mappers/snr_mapper.py +201 -0
  389. wxcli/migration/transform/mappers/softkey_mapper.py +205 -0
  390. wxcli/migration/transform/mappers/user_mapper.py +264 -0
  391. wxcli/migration/transform/mappers/voicemail_group_mapper.py +286 -0
  392. wxcli/migration/transform/mappers/voicemail_mapper.py +514 -0
  393. wxcli/migration/transform/mappers/workspace_mapper.py +464 -0
  394. wxcli/migration/transform/normalizers.py +2008 -0
  395. wxcli/migration/transform/pattern_converter.py +106 -0
  396. wxcli/migration/transform/pipeline.py +271 -0
  397. wxcli/migration/transform/rules.py +255 -0
  398. wxcli/org_health/CLAUDE.md +63 -0
  399. wxcli/org_health/__init__.py +7 -0
  400. wxcli/org_health/analyze.py +93 -0
  401. wxcli/org_health/checks.py +458 -0
  402. wxcli/org_health/collector.py +62 -0
  403. wxcli/org_health/models.py +78 -0
  404. wxcli/org_health/report.py +300 -0
  405. wxcli/output.py +101 -0
  406. wxcli-1.2.0.dist-info/METADATA +505 -0
  407. wxcli-1.2.0.dist-info/RECORD +413 -0
  408. wxcli-1.2.0.dist-info/WHEEL +5 -0
  409. wxcli-1.2.0.dist-info/entry_points.txt +2 -0
  410. wxcli-1.2.0.dist-info/licenses/LICENSE +191 -0
  411. wxcli-1.2.0.dist-info/scm_file_list.json +751 -0
  412. wxcli-1.2.0.dist-info/scm_version.json +8 -0
  413. wxcli-1.2.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,965 @@
1
+ # Authentication Reference — Webex Calling APIs
2
+
3
+ This document covers every authentication method available for the Webex Calling APIs, including token types, OAuth flows, scope requirements, and the `wxc_sdk` Python SDK patterns for each.
4
+
5
+ ## Sources
6
+
7
+ - wxc_sdk v1.30.0
8
+ - OpenAPI specs: specs/webex-cloud-calling.json, specs/webex-admin.json
9
+ - developer.webex.com Authentication APIs
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ 1. [Authentication Methods Overview](#authentication-methods-overview)
16
+ 2. [Personal Access Tokens](#personal-access-tokens)
17
+ 3. [OAuth Integrations](#oauth-integrations)
18
+ 4. [Service Apps](#service-apps)
19
+ 5. [Partner/Multi-Org Tokens](#partnerulti-org-tokens)
20
+ 6. [Bot Tokens](#bot-tokens)
21
+ 7. [Guest Issuer Tokens](#guest-issuer-tokens)
22
+ 8. [Calling-Related Scopes](#calling-related-scopes)
23
+ 8. [wxc_sdk Auth Setup](#wxc_sdk-auth-setup)
24
+ 9. [Raw HTTP via api.session](#raw-http-via-apisession)
25
+ 10. [Token Refresh Flow](#token-refresh-flow)
26
+ 11. [Common Auth Errors](#common-auth-errors)
27
+
28
+ ---
29
+
30
+ ## Authentication Methods Overview
31
+
32
+ | Method | Lifetime | Refresh? | Use Case | Calling API Access |
33
+ |--------|----------|----------|----------|-------------------|
34
+ | Personal Access Token | 12 hours | No | Dev/testing only | Full (your own scopes) |
35
+ | OAuth Integration | 14-day access / 90-day refresh | Yes | Production apps, user-delegated | Full (requested scopes) |
36
+ | Service App | Access token via refresh | Yes | Machine-to-machine, no user present | Full (admin-authorized scopes) |
37
+ | Bot Token | Does not expire | No | Automation, messaging-focused | Limited to bot scopes |
38
+ | Guest Issuer | Short-lived | No | Anonymous guest users | Not applicable to Calling |
39
+
40
+ All methods authenticate against the same base URL:
41
+
42
+ ```
43
+ https://webexapis.com/v1
44
+ ```
45
+
46
+ Every API request requires an `Authorization` header:
47
+
48
+ ```
49
+ Authorization: Bearer <ACCESS_TOKEN>
50
+ ```
51
+
52
+ ---
53
+
54
+ ## Personal Access Tokens
55
+
56
+ **What they are:** A quick-start token tied to your own Webex identity. Available from [developer.webex.com](https://developer.webex.com) by clicking your avatar and copying the token.
57
+
58
+ **Key facts:**
59
+ - Expires after **12 hours** from the time it is displayed
60
+ - Cannot be refreshed — you must generate a new one manually
61
+ - Carries most scopes your account has access to (including `spark-admin:*` scopes if you are an admin), but does NOT include Contact Center scopes (`cjp:config_read`, `cjp:config_write`). CC config operations require an OAuth integration with CC scopes explicitly selected.
62
+ - Intended strictly for development and testing — never embed in production code
63
+ - **Contact Center limitation:** Even full admins on CC-provisioned orgs get 403 on CC config endpoints (`api.wxcc-{region}.cisco.com`) with a PAT. Create an OAuth integration at developer.webex.com with `cjp:config_read` and `cjp:config_write` scopes, complete the OAuth flow, and use that token instead.
64
+
65
+ **wxc_sdk usage:**
66
+
67
+ ```python
68
+ from wxc_sdk import WebexSimpleApi
69
+
70
+ # Pass token directly as a string
71
+ api = WebexSimpleApi(tokens='YOUR_PERSONAL_ACCESS_TOKEN')
72
+
73
+ # Or set the environment variable and pass nothing
74
+ # export WEBEX_ACCESS_TOKEN=YOUR_PERSONAL_ACCESS_TOKEN
75
+ api = WebexSimpleApi()
76
+ ```
77
+
78
+ ---
79
+
80
+ ## OAuth Integrations
81
+
82
+ OAuth integrations use the **Authorization Code Grant** flow (OAuth 2.0). This is the standard method for production applications that act on behalf of a user.
83
+
84
+ ### Creating an Integration
85
+
86
+ 1. Log into [developer.webex.com](https://developer.webex.com)
87
+ 2. Click your avatar > **My Webex Apps** > **Create a New App** > **Create an Integration**
88
+ 3. Provide app name, description, logo, redirect URI, and select scopes
89
+ 4. Save the **Client ID** and **Client Secret** (secret shown only once)
90
+
91
+ ### OAuth Flow (4 Steps)
92
+
93
+ **Step 1 — Authorization Request:**
94
+ Redirect the user to:
95
+ ```
96
+ https://webexapis.com/v1/authorize?
97
+ client_id=YOUR_CLIENT_ID&
98
+ response_type=code&
99
+ redirect_uri=http://localhost:6001/redirect&
100
+ scope=spark:calls_read spark:calls_write spark:people_read spark-admin:telephony_config_read&
101
+ state=RANDOM_STATE_STRING
102
+ ```
103
+
104
+ **Step 2 — User Authenticates:**
105
+ User logs into Webex and approves the requested scopes.
106
+
107
+ **Step 3 — Receive Authorization Code:**
108
+ Webex redirects to your `redirect_uri` with a `code` parameter:
109
+ ```
110
+ http://localhost:6001/redirect?code=AUTH_CODE&state=RANDOM_STATE_STRING
111
+ ```
112
+
113
+ **Step 4 — Exchange Code for Tokens:**
114
+ POST to `https://webexapis.com/v1/access_token`:
115
+ ```
116
+ grant_type=authorization_code
117
+ client_id=YOUR_CLIENT_ID
118
+ client_secret=YOUR_CLIENT_SECRET
119
+ code=AUTH_CODE
120
+ redirect_uri=http://localhost:6001/redirect
121
+ ```
122
+
123
+ **Response:**
124
+ ```json
125
+ {
126
+ "access_token": "...",
127
+ "expires_in": 1209600,
128
+ "refresh_token": "...",
129
+ "refresh_token_expires_in": 7776000,
130
+ "token_type": "Bearer",
131
+ "scope": "spark:calls_read spark:calls_write ..."
132
+ }
133
+ ```
134
+
135
+ ### Token Lifetimes
136
+
137
+ | Token | Lifetime | Notes |
138
+ |-------|----------|-------|
139
+ | Access token | **14 days** (1,209,600 seconds) | Must refresh before expiry |
140
+ | Refresh token | **90 days** (7,776,000 seconds) | Refreshing the access token also renews the refresh token |
141
+
142
+ ### PKCE Support
143
+
144
+ Webex supports **Proof Key for Code Exchange (PKCE)** for enhanced security in the Authorization Code flow.
145
+
146
+ ### OpenID Connect Discovery
147
+
148
+ Endpoint locations and server capabilities are available at:
149
+ ```
150
+ https://idbroker.webex.com/idb/.well-known/openid-configuration
151
+ ```
152
+
153
+ This returns a standard OpenID Connect discovery document including `authorization_endpoint`, `token_endpoint`, `userinfo_endpoint`, `jwks_uri`, supported scopes (`openid`, `email`, `profile`, `phone`, `address`), and `code_challenge_methods_supported` (`plain`, `S256`).
154
+
155
+ ### Gotchas
156
+
157
+ - **wxc_sdk does not support PKCE natively.** The `Integration.auth_url()` method builds the authorization URL with only `client_id`, `response_type`, `redirect_uri`, `scope`, and `state` — no `code_challenge` or `code_challenge_method` parameters. The `tokens_from_code()` method does not send a `code_verifier`. To use PKCE with Webex, you would need to construct the authorization URL and token exchange manually.
158
+
159
+ ---
160
+
161
+ ## Service Apps
162
+
163
+ Service apps are designed for **machine-to-machine** scenarios where no interactive user login is possible (background jobs, server daemons, scheduled automation).
164
+
165
+ ### How They Differ from Integrations
166
+
167
+ | Aspect | Integration | Service App |
168
+ |--------|-------------|-------------|
169
+ | User presence | Requires user to authorize | No user interaction after admin approval |
170
+ | Token source | OAuth code flow | Refresh token provided at creation |
171
+ | Admin approval | User grants scopes | Org admin authorizes the app |
172
+ | Use case | User-facing apps | Backend automation, scheduled jobs |
173
+
174
+ ### Creating & Registering a Service App
175
+
176
+ Service app creation is a 3-step process spanning two portals: the Developer Portal (registration) and Control Hub (authorization).
177
+
178
+ #### Step 1: Register on developer.webex.com
179
+
180
+ 1. Log into [developer.webex.com](https://developer.webex.com)
181
+ 2. Click your avatar (top right) → **My Webex Apps**
182
+ 3. Click **Create a New App**
183
+ 4. Select **Create a Service App**
184
+ 5. Fill in the registration form:
185
+ - **App Name** — displayed to admins during authorization
186
+ - **Description** — what the app does
187
+ - **Logo** — appears in Control Hub when admins review the app
188
+ - **Scopes** — select the permissions your app needs (see [Calling-Related Scopes](#calling-related-scopes) below)
189
+ 6. Click **Create** (or **Add Service App**)
190
+ 7. **Immediately copy and save the Client Secret** — it is shown only once and cannot be retrieved later
191
+
192
+ You now have a **Client ID** and **Client Secret**. The app is registered but not yet authorized for any org.
193
+
194
+ #### Step 2: Authorize in Control Hub
195
+
196
+ An org Full Admin must authorize the service app before it can access that org's data.
197
+
198
+ 1. Log into [admin.webex.com](https://admin.webex.com)
199
+ 2. Navigate to **Management → Apps → Service Apps** tab
200
+ 3. Find your service app in the list
201
+ 4. Click it and select **Authorize**
202
+ 5. Review the requested scopes
203
+ 6. Click **Save**
204
+
205
+ The authorization is recorded in Admin Audit events. Any admin can later enable/disable the app from this same page.
206
+
207
+ #### Step 3: Generate Tokens
208
+
209
+ 1. Return to [developer.webex.com](https://developer.webex.com) → **My Webex Apps** → your service app
210
+ 2. In the **Org Authorizations** section, select your organization
211
+ 3. Enter your **Client Secret**
212
+ 4. Click **Generate Tokens**
213
+ 5. You receive:
214
+ - **Access Token** (valid 14 days)
215
+ - **Refresh Token** (valid 90 days)
216
+ 6. **Immediately copy and save the Refresh Token** — it is shown only once
217
+
218
+ Your service app is now ready to make API calls. Use the refresh token to obtain new access tokens programmatically (see below).
219
+
220
+ #### Scope Restrictions for Service Apps
221
+
222
+ Not all scopes work with service apps:
223
+
224
+ | Restriction | Detail |
225
+ |-------------|--------|
226
+ | XSI scopes | Not supported |
227
+ | Analytics scopes | Not supported |
228
+ | Organization contacts | Cannot manage |
229
+ | CDR records | Cannot query |
230
+ | Meeting scopes | Limited to `adminOnBehalf` functions (require `hostEmail` parameter) |
231
+ | Compliance scopes (`spark-compliance:*`) | Require Full Admin with Compliance Officer role |
232
+ | CJP scopes (`cjp:config_read`, `cjp:config_write`) | **Supported.** Select them at app creation in the developer portal. Confirmed by Cisco's "Introducing Service Apps for Webex Contact Center" blog post. `spark:applications_token` and `spark:kms` are NOT available for CC service apps — those require a separate OAuth integration. |
233
+ | CJDS scopes (`cjds:admin_org_read`, `cjds:admin_org_write`) | **Required for JDS admin APIs** (`/admin/v1/api/...` — workspace, person, template management). Standard `cjp:` scopes alone do NOT grant JDS admin access. The runtime profile view and event stream endpoints (`/v1/api/...`) may differ — verify per endpoint. Select these in addition to `cjp:` scopes when building JDS integrations. |
234
+ | Scope string length | Limited to ~880 characters total — only request what you need |
235
+
236
+ ### Authentication Flow
237
+
238
+ Service apps receive a **refresh token**, **client ID**, and **client secret** upon creation. They obtain access tokens by calling the same token endpoint used for integration refresh:
239
+
240
+ ```
241
+ POST https://webexapis.com/v1/access_token
242
+
243
+ grant_type=refresh_token
244
+ client_id=SERVICE_APP_CLIENT_ID
245
+ client_secret=SERVICE_APP_CLIENT_SECRET
246
+ refresh_token=SERVICE_APP_REFRESH_TOKEN
247
+ ```
248
+
249
+ The response includes a new `access_token` (and potentially a renewed `refresh_token`).
250
+
251
+ ### Token Lifecycle
252
+
253
+ | Token | Lifetime | Renewal |
254
+ |-------|----------|---------|
255
+ | Access token | 14 days | Refresh using refresh token |
256
+ | Refresh token | 90 days | 90-day expiry clock resets each time you make a refresh call (use the refresh token to generate a new access token). Simply using the access token does NOT reset it. |
257
+ | Client secret | Does not expire | Regenerate via developer portal if compromised |
258
+
259
+ **For long-lived automations**, Webex recommends a 3-tier pattern:
260
+
261
+ 1. **Tier 1:** Use the service app's refresh token to get new access tokens (normal operation)
262
+ 2. **Tier 2:** If the refresh token expires (90 days unused), use the Applications API with a separate OAuth integration to regenerate it
263
+ 3. **Tier 3:** The OAuth integration's own refresh token, refreshed by your token manager
264
+
265
+ This requires two Webex apps: your working service app and a token-manager integration. See the [Service App Token Management blog post](https://developer.webex.com/blog/service-app-token-management-a-developer-s-guide-to-automation) for details.
266
+
267
+ ### Environment Variables (Convention from wxc_sdk examples)
268
+
269
+ ```bash
270
+ SERVICE_APP_REFRESH_TOKEN=<refresh_token>
271
+ SERVICE_APP_CLIENT_ID=<client_id>
272
+ SERVICE_APP_CLIENT_SECRET=<client_secret>
273
+ ```
274
+
275
+ ### wxc_sdk Service App Pattern
276
+
277
+ From `examples/service_app.py` in the SDK:
278
+
279
+ ```python
280
+ from wxc_sdk import WebexSimpleApi
281
+ from wxc_sdk.integration import Integration
282
+ from wxc_sdk.tokens import Tokens
283
+
284
+ # Build an Integration object (used only for the refresh call)
285
+ integration = Integration(
286
+ client_id=client_id,
287
+ client_secret=client_secret,
288
+ scopes=[], # scopes not needed for refresh
289
+ redirect_url=None # no redirect needed for service apps
290
+ )
291
+
292
+ # Create a Tokens object with just the refresh token
293
+ tokens = Tokens(refresh_token=refresh_token)
294
+
295
+ # Refresh to get a valid access token
296
+ integration.refresh(tokens=tokens)
297
+
298
+ # Use the tokens
299
+ with WebexSimpleApi(tokens=tokens) as api:
300
+ users = list(api.people.list())
301
+ queues = list(api.telephony.callqueue.list())
302
+ ```
303
+
304
+ ### Token Caching
305
+
306
+ The SDK example caches tokens to a YML file keyed by `client_id` to avoid unnecessary refresh calls. It checks `tokens.remaining` and refreshes when remaining lifetime drops below 24 hours:
307
+
308
+ ```python
309
+ if tokens.expires_in is not None and tokens.remaining < 24 * 60 * 60:
310
+ tokens = get_access_token(client_id=client_id, client_secret=client_secret, refresh=refresh)
311
+ ```
312
+
313
+ ### Region Extraction from Token
314
+
315
+ Webex access tokens encode the CI (Common Identity) cluster and org ID directly in the token string. A production app can extract both without a separate API call:
316
+
317
+ ```python
318
+ parts = access_token.split('_')
319
+ # parts[0] = the access token value
320
+ # parts[1] = ciCluster (e.g. "us1", "eu1", "us2")
321
+ # parts[2] = orgId (base64-encoded Spark ID)
322
+ ci_cluster = parts[1]
323
+ ```
324
+
325
+ This is especially important for **Contact Center APIs**, which use a regional base URL rather than `webexapis.com`:
326
+
327
+ ```
328
+ https://api.wxcc-{ciCluster}.cisco.com
329
+ ```
330
+
331
+ For example, a token from a US org with `ciCluster = "us1"` hits `https://api.wxcc-us1.cisco.com`. The `get_cc_org_id()` helper in `wxcli/config.py` performs both the cluster extraction and the org ID decoding.
332
+
333
+ ---
334
+
335
+ ## Partner/Multi-Org Tokens
336
+
337
+ Partner/VAR/MSP admins hold tokens that have access to multiple customer organizations. Most Webex API endpoints accept an `orgId` query parameter to target a specific customer org; without it, the API defaults to the partner's own org (usually not what you want).
338
+
339
+ ### How wxcli handles partner tokens
340
+
341
+ wxcli detects multi-org tokens automatically and manages `orgId` injection transparently:
342
+
343
+ | Command | Purpose |
344
+ |---------|---------|
345
+ | `wxcli configure` | Detects whether the token has multi-org access. If so, lists available customer orgs and prompts you to select one. The chosen `orgId` is saved to the config file. |
346
+ | `wxcli switch-org` | Change the active target org at any time without re-running `configure`. |
347
+ | `wxcli clear-org` | Remove the saved `orgId` to revert to single-org (partner-org) behavior. |
348
+ | `wxcli whoami` | Shows a "Target: <org name>" line when a target org is set. |
349
+
350
+ Once a target org is configured, 668 of 804 generated commands automatically inject `orgId` from config on every API call that accepts the parameter — no `--org-id` flag required. The four hand-coded command files (users, licenses, locations, numbers) also inject `orgId` the same way.
351
+
352
+ ### Builder agent behavior
353
+
354
+ When the builder agent detects a partner token (section 2b of its workflow), it pauses and requires explicit org confirmation before proceeding. This prevents accidentally configuring the wrong customer org.
355
+
356
+ ### Scopes for partner tokens
357
+
358
+ Partner tokens use the same `spark-admin:` scopes as regular admin tokens. No additional scopes are required to access customer org data — the token type (partner) is what grants cross-org access, not a special scope.
359
+
360
+ ### Gotchas
361
+
362
+ - **`organizations list` returns multiple orgs for partner tokens.** wxcli uses this call to detect partner tokens: if the response contains more than one org, it treats the token as multi-org and prompts for selection. Single-org admins always see exactly one result.
363
+ - **Some endpoints do not accept `orgId`.** The 136 of 804 endpoints that do not accept `orgId` operate in the context of the token's own org. These are typically endpoints that are inherently org-scoped (e.g., `/v1/organizations/{orgId}/...` where the org is a path param, not a query param).
364
+ - **Service app tokens scoped to a single customer org** behave like single-org tokens and do not trigger multi-org detection.
365
+
366
+ ---
367
+
368
+ ## Bot Tokens
369
+
370
+ Bots are special Webex identities with their own access token.
371
+
372
+ **Key facts:**
373
+ - Bot tokens **do not expire** — they remain valid until the bot is deleted or regenerated
374
+ - No refresh token is provided (none needed)
375
+ - Bots have their own identity (separate from any user)
376
+ - Bots can interact with messaging, spaces, and webhooks
377
+ - Bot tokens have **limited scope for Calling APIs** — bots cannot place or manage calls on behalf of users
378
+
379
+ **wxc_sdk usage:**
380
+
381
+ ```python
382
+ from wxc_sdk import WebexSimpleApi
383
+
384
+ api = WebexSimpleApi(tokens='BOT_ACCESS_TOKEN')
385
+ ```
386
+
387
+ Since bot tokens never expire, no refresh logic is needed.
388
+
389
+ ### Gotchas
390
+
391
+ - **Bot calling scopes unverified.** The exact list of calling-related scopes available to bots (if any) has not been confirmed. The developer.webex.com docs list scopes with a `show_for_app_type` property for "integration" and "serviceApp" but do not enumerate bot-specific scopes. Calling scopes like `spark:calls_read` and `spark:calls_write` appear to be user-level scopes for integrations. Bots likely cannot use calling scopes since they don't act on behalf of a user, but this has not been confirmed with a live bot token. *(Unverified — requires live bot token testing. Checked 2026-03-19.)*
392
+
393
+ ---
394
+
395
+ ## Guest Issuer Tokens
396
+
397
+ > **⚠️ End of Life — December 31, 2025**
398
+ > The Guest Issuer API has been deprecated and reached End of Life on December 31, 2025. New Guest Issuer applications can no longer be created. Existing applications should migrate to **Service Apps** with guest management functionality. The section below is retained for reference only.
399
+
400
+ Guest Issuer tokens create temporary, anonymous guest users for scenarios like customer-facing meetings or support sessions.
401
+
402
+ **Key facts:**
403
+ - Managed via Service Apps with `guest-issuer:read` and `guest-issuer:write` scopes
404
+ - Guest tokens are short-lived
405
+ - **Not applicable to Webex Calling APIs** — guests cannot access telephony features
406
+
407
+ ### Gotchas
408
+
409
+ - **Guest token lifetime is variable, set by `expiresIn` in the response.** The OpenAPI spec example shows `expiresIn: 64799` (~6 hours), but the actual lifetime is returned per-token at creation time via the `expiresIn` field. The SDK `Guest` model exposes this as `expires_in` and computes `expires_at` from it. There is no single fixed lifetime — it depends on org/service-app configuration.
410
+
411
+ ---
412
+
413
+ ## Calling-Related Scopes
414
+
415
+ ### User-Level Scopes
416
+
417
+ These scopes operate in the context of the authenticated user. Any Webex Calling-licensed user can authorize these.
418
+
419
+ | Scope | Description |
420
+ |-------|-------------|
421
+ | `spark:calls_read` | List all active calls the user is part of; list call history from Webex Calling |
422
+ | `spark:calls_write` | Invoke call commands on the authenticated user (answer, hold, transfer, etc.) |
423
+ | `spark:xsi` | Access Webex Calling resources via XSI (calls and call settings) |
424
+ | `spark:webrtc_calling` | Access WebRTC services for Webex Calling |
425
+ | `spark:people_read` | Read people/user information (commonly needed alongside calling scopes) |
426
+ | `spark:kms` | Key Management Service — required for end-to-end encryption operations |
427
+
428
+ ### Admin-Level Scopes
429
+
430
+ These scopes require the authenticated user to be a **full org administrator**. They provide organization-wide access.
431
+
432
+ | Scope | Description |
433
+ |-------|-------------|
434
+ | `spark-admin:telephony_config_read` | Read and list telephony configuration (locations, numbers, call routing, features) |
435
+ | `spark-admin:telephony_config_write` | Create, edit, and delete telephony configuration |
436
+ | `spark-admin:calls_read` | List all calls across the organization |
437
+ | `spark-admin:calls_write` | Invoke call commands on any user in the organization |
438
+ | `spark-admin:calling_cdr_read` | Access comprehensive Call Detail Records, including PII-protected phone numbers |
439
+ | `spark-admin:people_read` | Read people across the organization |
440
+ | `spark-admin:people_write` | Create, update, delete people in the organization |
441
+
442
+ ### Scope Categories by API Function
443
+
444
+ **Administrator / Provisioning APIs** (require `spark-admin:` scopes):
445
+ - Telephony configuration (locations, numbers, call routing, auto attendants, call queues, hunt groups)
446
+ - CDR / reporting
447
+ - User/workspace provisioning
448
+
449
+ **End-User / Call Control APIs** (require `spark:` scopes):
450
+ - Call commands (dial, answer, hold, resume, transfer, park)
451
+ - Call history
452
+ - Voicemail
453
+ - Call settings (forwarding, DND, etc.)
454
+ - XSI-based operations
455
+
456
+ ### The `spark:all` Scope
457
+
458
+ The `spark:all` scope grants full access to a Webex account and allows applications to behave as native Webex clients, including calling features when using Webex SDKs. Use this scope sparingly — prefer requesting only the scopes your application needs.
459
+
460
+ ### Scope Parsing in wxc_sdk
461
+
462
+ The SDK includes a `parse_scopes` utility that handles multiple input formats — full authorization URLs, query strings, URL-encoded strings, or plain space-separated scope lists:
463
+
464
+ ```python
465
+ from wxc_sdk.scopes import parse_scopes
466
+
467
+ # All of these work:
468
+ scopes = parse_scopes('spark:calls_read spark:calls_write spark:people_read')
469
+ scopes = parse_scopes('spark%3Acalls_read%20spark%3Acalls_write')
470
+ scopes = parse_scopes('https://webexapis.com/v1/authorize?...&scope=spark%3Acalls_read%20...')
471
+ ```
472
+
473
+ ---
474
+
475
+ ## wxc_sdk Auth Setup
476
+
477
+ > **Note:** The async variant `AsWebexSimpleApi` (from `wxc_sdk.as_api`) accepts identical token arguments and initialization patterns. See `archive/wxc-sdk-patterns.md` section 4 for async usage details.
478
+
479
+ ### Initialization Patterns
480
+
481
+ The `WebexSimpleApi` class accepts tokens in three forms:
482
+
483
+ ```python
484
+ from wxc_sdk import WebexSimpleApi
485
+ from wxc_sdk.tokens import Tokens
486
+ ```
487
+
488
+ **Pattern 1 — String token (simplest, for dev/testing):**
489
+
490
+ ```python
491
+ api = WebexSimpleApi(tokens='YOUR_ACCESS_TOKEN')
492
+ ```
493
+
494
+ Internally, this wraps the string in a `Tokens(access_token='...')` object.
495
+
496
+ **Pattern 2 — Environment variable (no arguments):**
497
+
498
+ ```python
499
+ import os
500
+ os.environ['WEBEX_ACCESS_TOKEN'] = 'YOUR_ACCESS_TOKEN'
501
+
502
+ api = WebexSimpleApi() # reads from WEBEX_ACCESS_TOKEN
503
+ ```
504
+
505
+ If no `tokens` argument is provided and `WEBEX_ACCESS_TOKEN` is not set, a `ValueError` is raised:
506
+ ```
507
+ ValueError: if no access token is passed, then a valid access token has to be present in
508
+ WEBEX_ACCESS_TOKEN environment variable
509
+ ```
510
+
511
+ **Pattern 3 — Tokens object (for OAuth/service app flows):**
512
+
513
+ ```python
514
+ tokens = Tokens(
515
+ access_token='...',
516
+ refresh_token='...',
517
+ expires_in=1209600,
518
+ refresh_token_expires_in=7776000,
519
+ token_type='Bearer',
520
+ scope='spark:calls_read spark:calls_write'
521
+ )
522
+ tokens.set_expiration() # calculate expires_at from expires_in
523
+
524
+ api = WebexSimpleApi(tokens=tokens)
525
+ ```
526
+
527
+ **Pattern 4 — Pre-built RestSession:**
528
+
529
+ ```python
530
+ from wxc_sdk.rest import RestSession
531
+
532
+ session = RestSession(tokens=tokens, concurrent_requests=10, retry_429=True)
533
+ api = WebexSimpleApi(session=session)
534
+ ```
535
+
536
+ ### Constructor Parameters
537
+
538
+ ```python
539
+ WebexSimpleApi(
540
+ tokens: Union[str, Tokens] = None, # access token or Tokens object
541
+ concurrent_requests: int = 10, # max parallel requests (semaphore)
542
+ retry_429: bool = True, # auto-retry on rate limiting
543
+ session: RestSession = None, # pre-built session (overrides above)
544
+ )
545
+ ```
546
+
547
+ ### Context Manager Support
548
+
549
+ `WebexSimpleApi` supports the context manager protocol, which closes the underlying session on exit:
550
+
551
+ ```python
552
+ with WebexSimpleApi(tokens=tokens) as api:
553
+ me = api.people.me()
554
+ # session is automatically closed at the end of the block
555
+ ```
556
+
557
+ ### Full OAuth Integration Example
558
+
559
+ From `examples/get_tokens.py` — obtains tokens via OAuth flow, caches to YML, and initializes the API:
560
+
561
+ ```python
562
+ from dotenv import load_dotenv
563
+ from wxc_sdk import WebexSimpleApi
564
+ from wxc_sdk.integration import Integration
565
+ from wxc_sdk.scopes import parse_scopes
566
+ from wxc_sdk.tokens import Tokens
567
+
568
+ # Load environment variables
569
+ load_dotenv('get_tokens.env')
570
+
571
+ # Build integration from env vars
572
+ integration = Integration(
573
+ client_id=os.getenv('TOKEN_INTEGRATION_CLIENT_ID'),
574
+ client_secret=os.getenv('TOKEN_INTEGRATION_CLIENT_SECRET'),
575
+ scopes=parse_scopes(os.getenv('TOKEN_INTEGRATION_CLIENT_SCOPES')),
576
+ redirect_url='http://localhost:6001/redirect'
577
+ )
578
+
579
+ # Get tokens (reads from cache or initiates OAuth flow)
580
+ tokens = integration.get_cached_tokens_from_yml(yml_path='get_tokens.yml')
581
+
582
+ # Use the API
583
+ api = WebexSimpleApi(tokens=tokens)
584
+ me = api.people.me()
585
+ print(f'Authenticated as {me.display_name} ({me.emails[0]})')
586
+ ```
587
+
588
+ **Required `.env` file:**
589
+ ```bash
590
+ TOKEN_INTEGRATION_CLIENT_ID=Ce429631...
591
+ TOKEN_INTEGRATION_CLIENT_SECRET=a1b2c3d4...
592
+ TOKEN_INTEGRATION_CLIENT_SCOPES=spark:calls_read spark:calls_write spark:people_read spark-admin:telephony_config_read
593
+ ```
594
+
595
+ ---
596
+
597
+ ## Raw HTTP via api.session
598
+
599
+ <!-- Added by playbook session 2026-03-18 -->
600
+
601
+ The wxc_sdk `WebexSimpleApi` object is not just an SDK client — it also provides a pre-authenticated HTTP session you can use to call **any** Webex API endpoint directly, without going through typed SDK methods. This is the pattern used by the wxcli auto-generated commands.
602
+
603
+ ### Why Use Raw HTTP
604
+
605
+ - **Coverage gaps:** The SDK may not yet wrap every Webex Calling endpoint. Raw HTTP lets you call any documented (or undocumented) API.
606
+ - **Exact control:** You send the exact JSON body and query params the API expects, with no SDK data model translation.
607
+ - **Same auth:** The session inherits all authentication, token refresh, rate-limit retry, and concurrency control from the `WebexSimpleApi` you already set up.
608
+
609
+ ### How It Works
610
+
611
+ Initialize `WebexSimpleApi` using any auth method from the sections above. Then use `api.session.rest_*()` methods for direct HTTP calls:
612
+
613
+ ```python
614
+ from wxc_sdk import WebexSimpleApi
615
+
616
+ # Auth via environment variable (same as SDK usage)
617
+ # export WEBEX_ACCESS_TOKEN=YOUR_TOKEN
618
+ api = WebexSimpleApi()
619
+
620
+ BASE = "https://webexapis.com/v1"
621
+
622
+ # GET — list people
623
+ result = api.session.rest_get(f"{BASE}/people", params={"max": 100})
624
+ # result is a parsed JSON dict, e.g. {"items": [...]}
625
+
626
+ # POST — create a resource
627
+ body = {"displayName": "Test User", "emails": ["test@example.com"]}
628
+ result = api.session.rest_post(f"{BASE}/people", json=body)
629
+
630
+ # PUT — update a resource
631
+ api.session.rest_put(f"{BASE}/people/{person_id}", json=updated_body)
632
+
633
+ # DELETE — remove a resource
634
+ api.session.rest_delete(f"{BASE}/people/{person_id}")
635
+ ```
636
+
637
+ ### Available Session Methods
638
+
639
+ | Method | HTTP Verb | Returns | Notes |
640
+ |--------|-----------|---------|-------|
641
+ | `api.session.rest_get(url, params=...)` | GET | Parsed JSON dict | Use `params` for query string |
642
+ | `api.session.rest_post(url, json=...)` | POST | Parsed JSON dict | Use `json` for request body |
643
+ | `api.session.rest_put(url, json=...)` | PUT | Parsed JSON dict or `None` | Use `json` for request body |
644
+ | `api.session.rest_delete(url)` | DELETE | `None` | No response body |
645
+
646
+ ### Key Constraints
647
+
648
+ - **Full URLs required:** You must provide the complete URL including `https://webexapis.com/v1/...`. The session does not prepend a base URL.
649
+ - **No auto-pagination:** Unlike typed SDK methods (e.g., `api.people.list()`), raw HTTP calls return a single page. To paginate, pass `max=1000` and handle `next` links yourself.
650
+ - **Responses are plain dicts:** Results are parsed JSON dictionaries, not SDK model objects. Access fields with bracket notation (`result["items"]`), not dot notation.
651
+ - **Errors raise `RestError`:** All HTTP errors (401, 403, 404, 429, etc.) raise `wxc_sdk.rest.RestError`, just like typed SDK calls.
652
+
653
+ ### Auth Inheritance
654
+
655
+ The session inherits every auth behavior from `WebexSimpleApi`:
656
+
657
+ | Feature | Behavior with raw HTTP |
658
+ |---------|----------------------|
659
+ | `WEBEX_ACCESS_TOKEN` env var | Works — session reads the token automatically |
660
+ | `Tokens` object with refresh | Works — session refreshes transparently before expired requests |
661
+ | Service app tokens | Works — same `Integration.refresh()` flow, then pass `Tokens` to `WebexSimpleApi` |
662
+ | `retry_429=True` | Works — session retries rate-limited requests automatically |
663
+ | `concurrent_requests=10` | Works — session enforces the semaphore on raw HTTP calls too |
664
+ | Debug logging | Works — `Authorization` headers are masked as `Bearer ***` |
665
+
666
+ ### Complete Example: Service App + Raw HTTP
667
+
668
+ ```python
669
+ import os
670
+ from wxc_sdk import WebexSimpleApi
671
+ from wxc_sdk.integration import Integration
672
+ from wxc_sdk.tokens import Tokens
673
+
674
+ # Set up service app auth (identical to SDK pattern)
675
+ tokens = Tokens(refresh_token=os.getenv('SERVICE_APP_REFRESH_TOKEN'))
676
+ integration = Integration(
677
+ client_id=os.getenv('SERVICE_APP_CLIENT_ID'),
678
+ client_secret=os.getenv('SERVICE_APP_CLIENT_SECRET'),
679
+ scopes=[],
680
+ redirect_url=None
681
+ )
682
+ integration.refresh(tokens=tokens)
683
+
684
+ # Use the authenticated session for raw HTTP calls
685
+ BASE = "https://webexapis.com/v1"
686
+
687
+ with WebexSimpleApi(tokens=tokens) as api:
688
+ # List all locations
689
+ locations = api.session.rest_get(
690
+ f"{BASE}/locations", params={"max": 1000}
691
+ )
692
+ for loc in locations.get("items", []):
693
+ print(f"{loc['name']} ({loc['id']})")
694
+
695
+ # Read telephony config for a location
696
+ loc_id = locations["items"][0]["id"]
697
+ tele = api.session.rest_get(
698
+ f"{BASE}/telephony/config/locations/{loc_id}"
699
+ )
700
+ print(f"Calling line ID: {tele.get('callingLineId')}")
701
+ ```
702
+
703
+ ### When to Use SDK Methods vs Raw HTTP
704
+
705
+ | Situation | Use |
706
+ |-----------|-----|
707
+ | Endpoint is wrapped by wxc_sdk (e.g., `api.people.list()`) | SDK method — typed, paginated, validated |
708
+ | Endpoint is not in wxc_sdk yet | Raw HTTP via `api.session.rest_*()` |
709
+ | You need exact control over request body/params | Raw HTTP |
710
+ | You need auto-pagination over large result sets | SDK method (handles `next` links automatically) |
711
+ | Building CLI commands from Postman collections | Raw HTTP (the wxcli auto-gen pattern) |
712
+
713
+ ---
714
+
715
+ ## Token Refresh Flow
716
+
717
+ ### How the SDK Handles Refresh
718
+
719
+ The `Integration` class provides the refresh logic. Here is the flow:
720
+
721
+ 1. **Check remaining lifetime** via `tokens.remaining` (returns seconds until expiry)
722
+ 2. **If below threshold**, call `integration.refresh(tokens=tokens)` which POSTs to `https://webexapis.com/v1/access_token`
723
+ 3. **Tokens are updated in place** — the `access_token`, `expires_in`, `expires_at`, `refresh_token`, and `refresh_token_expires_at` fields are all refreshed
724
+
725
+ ```python
726
+ # Manual refresh check
727
+ if tokens.remaining < 300: # less than 5 minutes
728
+ integration.refresh(tokens=tokens)
729
+ ```
730
+
731
+ ### Automatic Token Validation
732
+
733
+ The `Integration.validate_tokens()` method encapsulates the check-and-refresh pattern:
734
+
735
+ ```python
736
+ changed = integration.validate_tokens(tokens=tokens, min_lifetime_seconds=300)
737
+ # changed=True means a refresh was attempted
738
+ # If refresh fails, tokens.access_token is set to None
739
+ ```
740
+
741
+ ### Cached Token Flow (get_cached_tokens)
742
+
743
+ The `Integration.get_cached_tokens()` method implements the full lifecycle:
744
+
745
+ 1. Read tokens from cache (callback-based — YML, database, etc.)
746
+ 2. Validate tokens (refresh if needed)
747
+ 3. If no valid token exists, initiate a full OAuth flow
748
+ 4. Write updated tokens back to cache
749
+
750
+ ```python
751
+ tokens = integration.get_cached_tokens_from_yml(
752
+ yml_path='tokens.yml',
753
+ force_new=False # set True to skip cache and force new OAuth flow
754
+ )
755
+ ```
756
+
757
+ ### The Tokens Model
758
+
759
+ ```python
760
+ class Tokens(BaseModel):
761
+ access_token: Optional[str] # the bearer token
762
+ expires_in: Optional[int] # lifetime in seconds at creation time
763
+ expires_at: Optional[datetime] # computed absolute expiry (UTC)
764
+ refresh_token: Optional[str] # refresh token
765
+ refresh_token_expires_in: Optional[int] # refresh token lifetime at creation
766
+ refresh_token_expires_at: Optional[datetime] # computed absolute expiry (UTC)
767
+ token_type: Optional[Literal['Bearer']] # always 'Bearer'
768
+ scope: Optional[str] # space-separated scope list
769
+ ```
770
+
771
+ Key methods:
772
+ - `set_expiration()` — computes `expires_at` and `refresh_token_expires_at` from current time + `expires_in`
773
+ - `remaining` — property returning seconds until access token expiry
774
+ - `update(new_tokens)` — copies all fields from another `Tokens` instance (used during refresh)
775
+
776
+ ### Service App Refresh (No OAuth Flow)
777
+
778
+ Service apps skip the authorization code flow entirely. They use only the refresh step:
779
+
780
+ ```python
781
+ # Service app environment variables
782
+ # SERVICE_APP_REFRESH_TOKEN, SERVICE_APP_CLIENT_ID, SERVICE_APP_CLIENT_SECRET
783
+
784
+ tokens = Tokens(refresh_token=os.getenv('SERVICE_APP_REFRESH_TOKEN'))
785
+ integration = Integration(
786
+ client_id=os.getenv('SERVICE_APP_CLIENT_ID'),
787
+ client_secret=os.getenv('SERVICE_APP_CLIENT_SECRET'),
788
+ scopes=[],
789
+ redirect_url=None
790
+ )
791
+ integration.refresh(tokens=tokens)
792
+
793
+ # tokens now has a valid access_token
794
+ api = WebexSimpleApi(tokens=tokens)
795
+ ```
796
+
797
+ ---
798
+
799
+ ## Common Auth Errors
800
+
801
+ ### HTTP 401 Unauthorized
802
+
803
+ **Causes:**
804
+ - Access token has expired (personal access token after 12 hours, integration token after 14 days)
805
+ - Token is malformed or has been revoked
806
+ - Missing `Authorization` header entirely
807
+ - Wrong token type (e.g., using a refresh token as an access token)
808
+
809
+ **SDK behavior:** Raises `RestError` with `response.status_code == 401`.
810
+
811
+ **Fix:** Refresh the token (for integrations/service apps) or generate a new personal access token.
812
+
813
+ ### HTTP 403 Forbidden
814
+
815
+ **Causes:**
816
+ - Token is valid but lacks the required scope for the endpoint
817
+ - Non-admin user trying to access `spark-admin:` endpoints
818
+ - Bot token trying to access calling endpoints it does not have permission for
819
+ - Service app not authorized by the org admin
820
+
821
+ **Common scope mismatches:**
822
+
823
+ | Attempted Action | Missing Scope |
824
+ |-----------------|---------------|
825
+ | Read telephony config | `spark-admin:telephony_config_read` |
826
+ | Modify call queue | `spark-admin:telephony_config_write` |
827
+ | Read call history | `spark:calls_read` |
828
+ | Control a call | `spark:calls_write` |
829
+ | Read CDR records | `spark-admin:calling_cdr_read` |
830
+
831
+ **Fix:** Verify the scopes on your integration/service app include what the endpoint requires. For admin scopes, confirm the authorizing user is a full org admin.
832
+
833
+ ### HTTP 429 Too Many Requests
834
+
835
+ **Cause:** Rate limiting. Webex APIs enforce per-token request limits.
836
+
837
+ **SDK behavior:** When `retry_429=True` (the default), the SDK automatically retries after the duration specified in the `Retry-After` response header, up to a maximum wait of 60 seconds (`RETRY_429_MAX_WAIT`).
838
+
839
+ **Response header:**
840
+ ```
841
+ Retry-After: 5
842
+ ```
843
+
844
+ ### Token Expiry Symptoms
845
+
846
+ | Symptom | Likely Cause |
847
+ |---------|-------------|
848
+ | 401 after exactly 12 hours | Personal access token expired |
849
+ | 401 after ~14 days | Integration access token expired, refresh needed |
850
+ | 401 immediately after refresh attempt | Refresh token also expired (>90 days) — full re-auth required |
851
+ | `tokens.remaining` returns 0 | Access token is not set or has expired |
852
+ | `ValueError` on `WebexSimpleApi()` | No token provided and `WEBEX_ACCESS_TOKEN` env var not set |
853
+
854
+ ### Error Response Format
855
+
856
+ Webex API errors return JSON with a tracking ID useful for support:
857
+
858
+ ```json
859
+ {
860
+ "message": "The request requires a valid access token set in the Authorization request header.",
861
+ "errors": [
862
+ {
863
+ "description": "The request requires a valid access token set in the Authorization request header."
864
+ }
865
+ ],
866
+ "trackingId": "ROUTER_6542a1b2-..."
867
+ }
868
+ ```
869
+
870
+ The SDK parses this into a `RestError` with `.detail` containing an `ErrorDetail` object:
871
+ - `error.detail.message` — the error message
872
+ - `error.detail.tracking_id` — the tracking ID for Webex TAC support
873
+ - `error.detail.description` — specific error description (from nested `errors` array)
874
+ - `error.detail.code` — numeric error code (when present)
875
+
876
+ ### Debugging Auth Issues
877
+
878
+ Enable SDK debug logging to see full request/response details (tokens are masked automatically):
879
+
880
+ ```python
881
+ import logging
882
+ logging.basicConfig(level=logging.DEBUG)
883
+ ```
884
+
885
+ The SDK masks `Authorization` headers as `Bearer ***` and redacts `access_token`, `refresh_token`, and `client_secret` values in logged output.
886
+
887
+ ---
888
+
889
+ ## Quick Reference: Which Auth Method to Use
890
+
891
+ | Scenario | Method | Notes |
892
+ |----------|--------|-------|
893
+ | Quick API test in terminal | Personal Access Token | Fastest to start, expires in 12h |
894
+ | Production app acting as a user | OAuth Integration | Standard OAuth 2.0 code flow |
895
+ | Nightly automation / cron job | Service App | No user interaction needed |
896
+ | Chatbot responding to messages | Bot Token | Does not expire, but limited calling access |
897
+ | One-off script during development | Personal Access Token or `WEBEX_ACCESS_TOKEN` env var | Use env var to avoid token in source code |
898
+ | CI/CD pipeline | Service App | Store credentials in secrets manager |
899
+ | Production CC app | Service App with CJP scopes | Select `cjp:config_read`/`cjp:config_write` at creation; regional base URL (`api.wxcc-{ciCluster}.cisco.com`) |
900
+
901
+ ---
902
+
903
+ ## Gotchas (Cross-Cutting)
904
+
905
+ - **call-controls requires user-level OAuth.** Admin tokens and service-app tokens get HTTP 400 "Target user not authorized" on `/telephony/calls` endpoints. Use a calling-licensed user's OAuth token for call control operations.
906
+ - **`spark-admin:` scopes require full org admin.** If the authorizing user is a read-only admin or compliance officer, requests to admin endpoints will return 403 even with the correct scopes listed on the integration.
907
+ - **Personal access tokens carry all scopes silently.** A personal access token for an org admin includes all `spark-admin:` scopes without requesting them, which can mask scope-related bugs that appear only in production integrations.
908
+ - **Service app refresh tokens can expire.** Although the initial refresh token is long-lived, if it is not used **to generate a new access token** within 90 days, it expires and the service app must be re-authorized by an org admin. Simply using the access token does not reset the 90-day clock — only making a refresh call does.
909
+
910
+ ---
911
+
912
+ ## Webex for Government (FedRAMP)
913
+
914
+ Webex for Government is a parallel deployment with separate URLs and feature restrictions.
915
+
916
+ ### Base URLs
917
+
918
+ | Service | Standard | FedRAMP |
919
+ |---------|----------|---------|
920
+ | API | `webexapis.com/v1` | `api-usgov.webex.com/v1` |
921
+ | Control Hub | `admin.webex.com` | `admin-usgov.webex.com` |
922
+ | Developer Portal | `developer.webex.com` | `developer-usgov.webex.com` |
923
+ | CDR/Analytics | `analytics.webexapis.com` | `analytics-calling-gov.webexapis.com` |
924
+
925
+ ### Feature Restrictions
926
+
927
+ These features/APIs are **not supported** in FedRAMP deployments:
928
+
929
+ | Feature | Reference Doc | Notes |
930
+ |---------|---------------|-------|
931
+ | DECT Devices | [devices-dect.md](devices-dect.md) | Entire DECT API excluded |
932
+ | Announcements & Playlists | [location-calling-media.md](location-calling-media.md) | Upload and playlist APIs excluded |
933
+ | Call Recording (location-level) | [location-recording-advanced.md](location-recording-advanced.md) | Recording vendor config excluded |
934
+ | Caller Reputation | [location-recording-advanced.md](location-recording-advanced.md) | Provider config excluded |
935
+ | Operating Modes | [call-features-additional.md](call-features-additional.md) | Mode management excluded |
936
+ | Hot Desking | [devices-dect.md](devices-dect.md) | Hot desk portal excluded |
937
+ | AA `directLineCallerIdName` | [call-features-major.md](call-features-major.md) | Use `firstName`/`lastName` instead |
938
+ | AA `dialByName` | [call-features-major.md](call-features-major.md) | Not available |
939
+ | 3rd-party device SIP mgmt | [devices-core.md](devices-core.md) | `line_port`, `sip_user_name` retrieval and SIP password modification |
940
+ | UC-One settings | [person-call-settings-behavior.md](person-call-settings-behavior.md) | UC Manager Profile config |
941
+ | MS Teams integration | [person-call-settings-behavior.md](person-call-settings-behavior.md) | MS Teams calling settings |
942
+
943
+ ### Authentication Differences
944
+
945
+ - **Service App tokens** (`spark:applications_token` scope): NOT supported in FedRAMP
946
+ - **Bot/Integration creation**: Must use REST API (`POST /applications`), not the developer portal UI
947
+ - **Application webhooks** (`application:webhooks_write/read`): NOT supported
948
+ - **OAuth integration refresh token lifetime:** 60 days in FedRAMP (vs. 90 days in commercial). The 60-day clock resets each time a refresh call is made.
949
+ - **Guest Issuer tokens:** Not supported in FedRAMP (and globally EOL'd December 31, 2025 — see Guest Issuer section).
950
+
951
+ ### wxcli Usage
952
+
953
+ Set the base URL before running commands:
954
+
955
+ ```bash
956
+ # Configure wxcli for FedRAMP
957
+ wxcli configure --base-url https://api-usgov.webex.com/v1
958
+ ```
959
+
960
+ ---
961
+
962
+ ## See Also
963
+
964
+ - **`provisioning.md`** — Provisioning-specific scope requirements and end-to-end user/license/location provisioning workflows.
965
+ - **`archive/wxc-sdk-patterns.md`** — SDK code recipes, async auth patterns, and the service app token caching pattern (section 3, Pattern D). Archived: historical SDK doc.