Skip to content

Architecture

The SDK is built around a two-tier credential model, async-first API design, and an optional gRPC media server for live BYOVA voice sessions.

Two-tier credentials

flowchart TB
  subgraph dev [Developer tier]
    Integration[Integration OAuth]
    Webhooks[Webhook registration]
  end
  subgraph org [Per-org tier]
    ServiceApp[Service App tokens]
    DataSources[DataSource CRUD]
    Schemas[Schema discovery]
  end
  Integration --> ServiceApp
  Integration --> Webhooks
  ServiceApp --> DataSources
  ServiceApp --> Schemas
Tier Who authorizes SDK component Purpose
Integration Developer (you) IntegrationTokenManager OAuth, webhooks, fetch org tokens
Service App Customer admin ServiceAppTokenManager Per-org API access

See Credentials for field details.

BYOVA media server (optional)

The webex_byova.media module is installed separately via pip install webex-byova[media]. It does not change existing BYODS REST APIs.

flowchart LR
  WX[Webex Contact Center]
  MS[BYOVAMediaServer]
  H[Your handlers]
  P[WebSocketProxyConnector]
  AI[External voice AI]
  WX <-->|gRPC| MS
  MS --> H
  MS -.->|optional| P
  P <-->|WebSocket| AI
Component Module Role
BYOVAMediaServer webex_byova.media Async gRPC server; registers event handlers
MediaSession / TurnContext webex_byova.media Per-call session and turn lifecycle
MediaServerConfig webex_byova.media Host, port, audio mode, TLS, token verification
WebSocketProxyConnector webex_byova.media.proxy Forward media/events to external backends
Protocol adapter webex_byova.media._internal Protobuf/gRPC — not part of the public API

Webex connects to your server as a gRPC client. You implement conversational logic with decorators such as @server.on("session_start") — no protobuf types required. See Media Server Overview.

Token verification reuses the same JWSVerifier as BYODS when verify_tokens=True (default).

Multi-tenant org model

Each customer organization that authorizes your Service App gets its own token pair stored via TokenStorage. Use BYOVA.aget_client_for_org(org_id) to obtain an OrgClient scoped to that org:

client = await sdk.aget_client_for_org(org_id)
await client.data_sources.acreate({...})
schemas = await client.schemas.alist()

The SDK raises OrgNotRegisteredError if you request a client for an org without stored tokens. Register orgs via webhooks or service_app.asave_registration() — see Authentication.

Async-first conventions

All resource methods use the a* prefix (alist, acreate, aauthorize). Sync wrappers exist on select entry points (authorize, get_client_for_org, verify_jws_token) for convenience; they delegate to asyncio.run().

The media server is async-only — handlers may be sync functions; the server runs them via asyncio.to_thread.

Recommended pattern (BYODS):

import asyncio
from webex_byova import BYOVA

async def main():
    sdk = BYOVA.from_env()
    try:
        await sdk.integration.aauthorize()
        # ... async API calls ...
    finally:
        await sdk.aclose()

asyncio.run(main())

Recommended pattern (media server):

import asyncio
from webex_byova.media import BYOVAMediaServer

async def main():
    server = BYOVAMediaServer.from_env()

    @server.on("session_start")
    async def greet(session, turn):
        await turn.play_prompt(text="Hello")

    async with server:
        await server._grpc_server.wait_for_termination()

asyncio.run(main())

Always call aclose() on BYOVA when done to release HTTP connections.

Component overview

Component Module Role
BYOVA webex_byova Facade wiring all BYODS subsystems
IntegrationTokenManager webex_byova.auth Developer OAuth flow
ServiceAppTokenManager webex_byova.auth Per-org token fetch/refresh
WebhookManager webex_byova.webhooks Register serviceApp hooks
OrgClient webex_byova.resources Org-scoped DataSource + Schema APIs
JWSVerifier webex_byova.jws Verify inbound data tokens
BYOVAMediaServer webex_byova.media BYOVA gRPC media server (optional extra)

For the full API surface, see webex_byova and webex_byova.media.