Skip to content

feat: implement backend-controlled zoom RTMS start endpoint#16

Merged
CyberwizD merged 4 commits into
mainfrom
feat/zoom-sdk-integration
May 17, 2026
Merged

feat: implement backend-controlled zoom RTMS start endpoint#16
CyberwizD merged 4 commits into
mainfrom
feat/zoom-sdk-integration

Conversation

@CyberwizD
Copy link
Copy Markdown
Collaborator

@CyberwizD CyberwizD commented May 17, 2026

Description

Adds backend-controlled Zoom RTMS start support so the SDK can request RTMS manually instead of depending only on Zoom auto-start. This includes Zoom OAuth token exchange/storage, RTMS control API integration, and a new session endpoint for starting RTMS on an active Zoom meeting.

Type of Change

  • feat — New feature
  • fix — Bug fix
  • refactor — Code refactoring (no functional change)
  • docs — Documentation update
  • test — Adding or updating tests
  • chore — Maintenance (dependencies, CI, tooling)

Related Issue

Closes #

Changes Made

  • Added Zoom OAuth token exchange and storage through /api/v1/zoom/oauth/callback.
  • Added sdk_zoom_oauth_tokens table for storing Zoom access/refresh tokens and expiry metadata.
  • Added Zoom RTMS control client for calling Zoom’s RTMS app status endpoint.
  • Added POST /api/v1/sdk/sessions/{session_id}/rtms/start to manually request RTMS start for an active Zoom meeting.
  • Updated SDK config with Zoom API/token URLs and optional temporary access-token override.
  • Updated docs and env examples for the manual RTMS start flow.
  • Added tests for OAuth token retrieval and RTMS start request payload.

Proof of Work

API Response / Screenshots
POST /api/v1/sdk/sessions/{session_id}/rtms/start
Status: 202 Accepted

{
  "status": true,
  "message": "Zoom RTMS start requested",
  "data": {
    "session": {
      "id": "session-id",
      "platform": "zoom",
      "meeting_id": "86429575325",
      "status": "rtms_start_requested"
    },
    "zoom": {
      "action": "start",
      "meeting_id": "86429575325",
      "zoom_status_code": 202,
      "zoom_response": {
        "status": "requested"
      }
    }
  }
}

Test Cases

  • Test case 1: test_zoom_oauth_client_uses_stored_access_token
  • Test case 2: test_zoom_rtms_start_posts_expected_payload
  • Test case 3: test_database_url_normalizes_asyncpg_override_for_sync_sdk
  • Test case 4: test_duplicate_provider_event_returns_existing_event
Test output
make lint
# All checks passed!
uv run pytest tests\sdk -q
# 23 passed

Checklist

  • My branch follows the naming convention (/)
  • My commits follow Conventional Commits
  • I have added meaningful tests that cover success and failure paths
  • All new and existing tests pass locally (uv run pytest)
  • I have included proof of work (JSON responses or screenshots)
  • I have updated documentation if needed
  • My code follows the project's style guidelines

Summary by CodeRabbit

  • New Features

    • Zoom RTMS (Real-Time Meeting Services) integration for managing real-time meeting sessions.
    • OAuth token exchange and management for Zoom authentication.
    • New API endpoint to initiate RTMS for a session with optional participant selection.
    • Configuration support for Zoom API and OAuth endpoints.
  • Documentation

    • Updated Zoom RTMS SDK documentation with OAuth authorization flow and RTMS initialization examples.
  • Tests

    • Added test coverage for Zoom OAuth token handling and RTMS control operations.

Review Change Stack

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 17, 2026

Warning

Rate limit exceeded

@CyberwizD has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 28 minutes and 22 seconds before requesting another review.

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: e753fc7d-91c8-45bd-81d0-fc9b382d287d

📥 Commits

Reviewing files that changed from the base of the PR and between eb16a42 and a7cf8e3.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (14)
  • .env.example
  • app/api/v1/routes/zoom_sdk.py
  • docs/sdk/zoom-rtms-sdk-prototype.md
  • pyproject.toml
  • sdk/config.py
  • sdk/models.py
  • sdk/providers/zoom_rtms/control.py
  • sdk/providers/zoom_rtms/oauth.py
  • sdk/providers/zoom_rtms/oauth_state.py
  • sdk/repositories.py
  • sdk/schemas.py
  • sdk/security.py
  • tests/sdk/test_zoom_oauth_state.py
  • tests/sdk/test_zoom_rtms_control.py
📝 Walkthrough

Walkthrough

This PR adds Zoom RTMS (Real-Time Messaging Service) support to the SDK by implementing OAuth token management, RTMS control operations, data persistence, and corresponding API endpoints. Configuration variables and database models are established, OAuth code exchange and token refresh logic is implemented, the RTMS control client is added, and tests and documentation are updated.

Changes

Zoom RTMS OAuth and Control Integration

Layer / File(s) Summary
Configuration and data models
.env.example, sdk/config.py, sdk/models.py, sdk/schemas.py
Environment variables for Zoom API and OAuth endpoints are added and loaded into SDKSettings. New SDKZoomOAuthToken ORM model persists tokens with access/refresh token fields, expiration, and timestamps. OAuthCallbackResponse extends with token_stored flag; StartRTMSRequest and RTMSControlResponse schemas are introduced.
Zoom OAuth token management
sdk/providers/zoom_rtms/oauth.py, sdk/repositories.py, app/api/v1/routes/zoom_sdk.py
ZoomOAuthClient exchanges authorization codes for tokens via httpx.post, handles refresh using refresh-token grant, and retrieves access tokens from settings or stored database records. SDKRepository adds methods to save/query tokens with expiration logic that normalizes naive datetimes to UTC. OAuth callback handler is updated to accept db dependency, call exchange_code, convert errors to HTTP 400, and set token_stored flag.
RTMS control and SDK integration
sdk/providers/zoom_rtms/control.py, sdk/sdk.py, app/api/v1/routes/sdk.py
ZoomRTMSControlClient wraps RTMS start/stop operations by posting to Zoom RTMS status endpoint with OAuth bearer token, handling responses and errors. MeetMindSDK.start_zoom_rtms() validates meeting_id, calls control client, and updates session status to rtms_start_requested. New POST /sessions/{session_id}/rtms/start API endpoint loads session, validates Zoom platform, invokes SDK method, maps exceptions to HTTP status codes (401/502/400), and returns session plus RTMS result.
Tests and documentation
tests/sdk/test_zoom_rtms_control.py, docs/sdk/zoom-rtms-sdk-prototype.md
Pytest fixture creates isolated SQLite database per test with ORM table initialization. Tests verify ZoomOAuthClient.get_access_token() retrieves stored tokens and verify ZoomRTMSControlClient.start() sends correct HTTP request with Authorization header and JSON payload. Documentation updates include Zoom API configuration variables in local setup and expanded Prototype Flow with explicit OAuth authorization step and RTMS start API call example.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant OAuthCallback as OAuth Callback Handler
  participant OAuthClient as ZoomOAuthClient
  participant ZoomOAuth as Zoom OAuth Endpoint
  participant Repository as SDKRepository
  participant Database as Database
  Client->>OAuthCallback: GET /oauth/callback?code=AUTH_CODE
  OAuthCallback->>OAuthClient: exchange_code(AUTH_CODE)
  OAuthClient->>ZoomOAuth: POST /oauth/token (code grant)
  ZoomOAuth-->>OAuthClient: token_payload (access/refresh/expires)
  OAuthClient->>Repository: save_zoom_oauth_token(payload)
  Repository->>Database: INSERT SDKZoomOAuthToken
  Database-->>Repository: token record
  Repository-->>OAuthClient: saved token
  OAuthClient-->>OAuthCallback: token JSON
  OAuthCallback-->>Client: OAuthCallbackResponse (token_stored=true)
Loading
sequenceDiagram
  participant Client
  participant SDKEndpoint as SDK API Endpoint
  participant SDK as MeetMindSDK
  participant ControlClient as ZoomRTMSControlClient
  participant OAuthClient as ZoomOAuthClient
  participant ZoomRTMS as Zoom RTMS Endpoint
  participant Repository as SDKRepository
  Client->>SDKEndpoint: POST /sessions/{id}/rtms/start (participant_user_id?)
  SDKEndpoint->>SDKEndpoint: Load session, validate Zoom
  SDKEndpoint->>SDK: start_zoom_rtms(session, participant_user_id)
  SDK->>ControlClient: start(meeting_id, participant_user_id)
  ControlClient->>OAuthClient: get_access_token()
  OAuthClient-->>ControlClient: access_token
  ControlClient->>ZoomRTMS: POST /status (action, client_id, participant_user_id)
  ControlClient->>ControlClient: Authorization Bearer token
  ZoomRTMS-->>ControlClient: response (status_code, payload)
  ControlClient-->>SDK: result dict (action, meeting_id, code, response)
  SDK->>Repository: update_session(rtms_start_requested)
  Repository-->>SDK: session updated
  SDK-->>SDKEndpoint: control result
  SDKEndpoint-->>Client: session + zoom start result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main feature: implementing a backend-controlled Zoom RTMS start endpoint, which is the primary focus of this PR.
Description check ✅ Passed The description is comprehensive, covering the main feature, related changes, changes made, proof of work with API response, test cases with output, and a completed checklist matching the template requirements.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/zoom-sdk-integration

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@app/api/v1/routes/zoom_sdk.py`:
- Around line 39-47: The callback handler currently calls
ZoomOAuthClient(db).exchange_code(code) without validating the incoming state;
before calling exchange_code (in the same function handling code: str | None and
state: str | None), fetch the server-stored nonce for this user/session from the
DB (or session store) and compare it to the incoming state, and if they do not
match raise/return an HTTPException (403/400) or otherwise abort the request;
only proceed to call ZoomOAuthClient(db).exchange_code(code) when the state
matches, and ensure any ZoomOAuthError handling remains after this validation.

In `@sdk/models.py`:
- Around line 134-136: The access_token and refresh_token columns are stored
plaintext; change them to store encrypted blobs and perform transparent
encryption/decryption around persistence: replace direct use of
access_token/refresh_token mapped_columns with encrypted storage columns (e.g.,
access_token_encrypted, refresh_token_encrypted) and expose plaintext via
properties or ORM event hooks on the model class (the class containing
access_token/access_refresh_token mapped_columns in sdk/models.py). Implement
and call a central encrypt_token(value) and decrypt_token(value) utility that
uses your KMS/app envelope key before insert/update and after load, and ensure
token_type and any index/unique constraints are preserved; update
create/update/read paths to use the plaintext properties so callers are
unchanged. Ensure null handling for refresh_token and add tests for round-trip
encryption/decryption.

In `@sdk/providers/zoom_rtms/control.py`:
- Around line 61-70: The httpx.post call in Zoom RTMS control (around the block
using self.settings.zoom_api_base_url, meeting_id, access_token and
parse_zoom_response) can raise httpx.RequestError on network failures and is not
currently caught; wrap the httpx.post invocation in a try/except that catches
httpx.RequestError as e and re-raises a ZoomRTMSControlError with the error
details (e.g., raise ZoomRTMSControlError(str(e)) from e) so network errors are
mapped to the same domain error type before you continue to use response and
response_payload.

In `@sdk/providers/zoom_rtms/oauth.py`:
- Around line 24-35: The httpx.post() calls that build OAuth token and revoke
requests (the blocks creating response = httpx.post(...) using
self.settings.zoom_oauth_token_url and the later httpx.post(...) for revoke)
must be wrapped in try/except that catches httpx.RequestError (and subclasses)
and raises ZoomOAuthError with the original exception message; keep the existing
HTTP status_code check after a successful request. Locate the two response =
httpx.post(...) occurrences in oauth.py and surround each with a try: ... except
httpx.RequestError as exc: raise ZoomOAuthError(f"Zoom HTTP transport error:
{exc}") to convert transport-level failures into ZoomOAuthError for consistent
error handling.

In `@sdk/repositories.py`:
- Around line 203-204: The current early-return returns a token when
token.expires_at is None which treats unknown-expiry tokens as usable; change
the conditional around the token variable so that if token is None or
token.expires_at is None the function returns None (not token) so the
caller/refresh logic will treat missing expiry as non-usable and force a
refresh; update the if block that checks "if token is None or token.expires_at
is None:" to return None.

In `@tests/sdk/test_zoom_rtms_control.py`:
- Around line 68-70: The assertion currently hard-codes a specific client_id in
the raw bytes from requests[0].read(), which is brittle; instead, decode and
parse the request body from requests[0].read(), then assert the JSON structure
and that settings.client_id equals the test's actual client id (e.g., the client
id variable used to construct the RTMS control request) or compare against the
value extracted from the request/fixture rather than the literal
"3iMvy78ESDa9JkWUgH3oXg". Locate the assertion on requests[0].read(), replace
the byte-string equality with parsing the body (JSON), assert action=="start"
and settings exists, and assert settings["client_id"] matches the dynamic client
id variable or extracted expected value.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 76aa17b3-c9f1-49db-8694-d2ab466837b9

📥 Commits

Reviewing files that changed from the base of the PR and between 91f8b2d and eb16a42.

📒 Files selected for processing (12)
  • .env.example
  • app/api/v1/routes/sdk.py
  • app/api/v1/routes/zoom_sdk.py
  • docs/sdk/zoom-rtms-sdk-prototype.md
  • sdk/config.py
  • sdk/models.py
  • sdk/providers/zoom_rtms/control.py
  • sdk/providers/zoom_rtms/oauth.py
  • sdk/repositories.py
  • sdk/schemas.py
  • sdk/sdk.py
  • tests/sdk/test_zoom_rtms_control.py

Comment thread app/api/v1/routes/zoom_sdk.py Outdated
Comment thread sdk/models.py Outdated
Comment thread sdk/providers/zoom_rtms/control.py Outdated
Comment thread sdk/providers/zoom_rtms/oauth.py Outdated
Comment thread sdk/repositories.py Outdated
Comment thread tests/sdk/test_zoom_rtms_control.py Outdated
@CyberwizD CyberwizD merged commit 7d7644a into main May 17, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant