Zoom Meeting SDK (Windows)

SkillWeb & browsing

Zoom Meeting SDK for Windows - Native C++ SDK for embedding Zoom meetings into Windows desktop applications. Supports custom UI architecture with raw video/audio data, headless bots, and deep integration with meeting features. Includes SDK architecture patterns and Windows message loop handling.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the Zoom Meeting SDK (Windows) skill

What this skill tells your AI

The instructions your AI receives, as published by zoom/skills in skills/meeting-sdk/windows/SKILL.md and read by ahel’s review.

Embed Zoom meeting capabilities into Windows desktop applications for native C++ integrations and headless bots.

Version boundary: The public changelog's current Windows release is 7.1.0 (verified 2026-07-10), while detailed interface inventories in this skill were generated from 6.7.2.26830. Version 7.1.0 includes breaking changes, a VC++ runtime DLL upgrade, I420 Limited/Full, breakout-room summaries, face ROI in raw video, and on-demand avatar download. Diff the 7.1.0 headers, required virtual methods, DLL set, and samples before upgrading.

New to Zoom SDK? Start Here!

The fastest way to master the SDK:

  1. SDK Architecture Pattern - Learn the universal pattern that works for ALL 35+ features
  2. Authentication Pattern - Get a working bot joining meetings
  3. Windows Message Loop - Fix the #1 reason callbacks don't fire

Building a Custom UI?

Having issues?

Prerequisites

  • Zoom app with Meeting SDK credentials (Client ID & Secret)
  • Visual Studio 2019/2022 or later
  • Windows 10 or later
  • C++ development environment
  • vcpkg for dependency management

Need help with authentication? See the zoom-oauth skill for JWT token generation.

Project Preferences & Learnings

IMPORTANT: These are hard-won preferences from real project experience. Follow these when creating new projects.

Do NOT use CMake — Use native Visual Studio .vcxproj

Always create a native Visual Studio .sln + .vcxproj project, not a CMake project. Reasons:

  • More standard and familiar for Windows C++ developers
  • Developers can double-click the .sln to open in Visual Studio immediately
  • Project settings (include dirs, lib dirs, preprocessor defines) are easier to see and edit in the VS Property Pages UI
  • No extra CMake tooling or configuration step required
  • Friendlier and easier for developers to understand and maintain

config.json must be visible in Solution Explorer

The config.json file (containing sdk_jwt, meeting_number, passcode) must be:

  1. Included in the .vcxproj as a <None> item with <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  2. Placed in a "Config" filter in the .vcxproj.filters file so it appears under a "Config" folder in Solution Explorer
  3. Easily editable by developers directly from Solution Explorer — they should never have to hunt for it in File Explorer

Example .vcxproj entry:

<ItemGroup>
  <None Include="config.json">
    <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  </None>
</ItemGroup>

Example .vcxproj.filters entry:

<ItemGroup>
  <Filter Include="Config">
    <UniqueIdentifier>{GUID-HERE}</UniqueIdentifier>
  </Filter>
</ItemGroup>
<ItemGroup>
  <None Include="config.json">
    <Filter>Config</Filter>
  </None>
</ItemGroup>

Overview

The Windows SDK is a C++ native SDK designed for:

  • Desktop applications - Native Windows apps with full UI control
  • Headless bots - Join meetings without UI
  • Raw media access - Capture/send audio/video streams
  • Local recording - Record meetings locally or to cloud

Key Architectural Insight

The SDK follows a universal 3-step pattern for every feature:

  1. Get controller (singleton): meetingService->Get[Feature]Controller()
  2. Implement event listener: class MyListener : public I[Feature]Event { ... }
  3. Register and use: controller->SetEvent(listener) then call methods

This works for ALL features: audio, video, chat, recording, participants, screen sharing, breakout rooms, webinars, Q&A, polling, whiteboard, and 20+ more!

Learn more: SDK Architecture Pattern Guide

Quick Start

1. Download Windows SDK

Download from Zoom Marketplace:

  • Extract zoom-meeting-sdk-windows_x86_64-{version}.zip

2. Setup Project Structure

your-project/
  YourApp/
    SDK/
      x64/
        bin/          # DLL files and dependencies
        h/            # Header files
        lib/          # sdk.lib
      x86/
        bin/
        h/
        lib/
    YourApp.cpp
    YourApp.vcxproj
    config.json

Copy SDK files:

xcopy /E /I sdk-package\x64 your-project\YourApp\SDK\x64\
xcopy /E /I sdk-package\x86 your-project\YourApp\SDK\x86\

3. Install Dependencies (vcpkg)

# Install vcpkg
git clone https://github.com/Microsoft/vcpkg.git C:\vcpkg
cd C:\vcpkg
.\bootstrap-vcpkg.bat
.\vcpkg integrate install

# Install dependencies
.\vcpkg install jsoncpp:x64-windows
.\vcpkg install curl:x64-windows

4. Configure Visual Studio Project

Project Properties → C/C++ → General → Additional Include Directories:

$(SolutionDir)SDK\$(PlatformTarget)\h
C:\vcpkg\packages\jsoncpp_x64-windows\include
C:\vcpkg\packages\curl_x64-windows\include

Project Properties → Linker → General → Additional Library Directories:

$(SolutionDir)SDK\$(PlatformTarget)\lib

Project Properties → Linker → Input → Additional Dependencies:

sdk.lib

Post-Build Event (Copy DLLs to output):

xcopy /Y /D "$(SolutionDir)SDK\$(PlatformTarget)\bin\*.*" "$(OutDir)"

5. Configure Credentials

Create config.json:

{
  "sdk_jwt": "YOUR_JWT_TOKEN",
  "meeting_number": "1234567890",
  "passcode": "password123",
  "zak": ""
}

6. Build & Run

  • Open solution in Visual Studio
  • Select x64 or x86 configuration
  • Press F5 to build and run

Core Workflow

┌─────────────┐    ┌─────────────┐    ┌─────────────┐    ┌─────────────┐
│  InitSDK    │───►│  AuthSDK    │───►│ JoinMeeting │───►│ Raw Data    │
│             │    │  (JWT)      │    │             │    │ Subscribe   │
└─────────────┘    └─────────────┘    └─────────────┘    └─────────────┘
                         │                   │
                         ▼                   ▼
                   OnAuthComplete      onInMeeting
                     callback           callback

⚠️ CRITICAL: Add Windows message loop or callbacks won't fire!

while (!done) {
    MSG msg;
    while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

See: Windows Message Loop Guide

Code Examples

💡 Pro Tip: These are minimal examples. For complete, tested code see:

Important: Include Order

CRITICAL: Include headers in this exact order or you'll get build errors:

#include <windows.h>      // MUST be first
#include <cstdint>         // MUST be second (SDK headers use uint32_t)
// ... other standard headers ...
#include <zoom_sdk.h>
#include <meeting_service_components/meeting_audio_interface.h>  // BEFORE participants!
#include <meeting_service_components/meeting_participants_ctrl_interface.h>

See: Build Errors Guide for all dependency fixes.

1. Initialize SDK

#include <windows.h>
#include <cstdint>
#include <zoom_sdk.h>

using namespace ZOOM_SDK_NAMESPACE;

bool InitMeetingSDK() {
    InitParam initParam;
    initParam.strWebDomain = L"https://zoom.us";
    initParam.strSupportUrl = L"https://zoom.us";
    initParam.emLanguageID = LANGUAGE_English;
    initParam.enableLogByDefault = true;
    initParam.enableGenerateDump = true;
    
    SDKError err = InitSDK(initParam);
    if (err != SDKERR_SUCCESS) {
        std::wcout << L"InitSDK failed: " << err << std::endl;
        return false;
    }
    return true;
}

2. Authenticate with JWT

#include <windows.h>
#include <cstdint>
#include <auth_service_interface.h>
#include "AuthServiceEventListener.h"

IAuthService* authService = nullptr;

void OnAuthenticationComplete() {
    std::cout << "Authentication successful!" << std::endl;
    JoinMeeting();  // Proceed to join meeting
}

bool AuthenticateSDK(const std::wstring& jwtToken) {
    CreateAuthService(&authService);
    if (!authService) return false;
    
    // Set event listener BEFORE calling SDKAuth
    authService->SetEvent(new AuthServiceEventListener(&OnAuthenticationComplete));
    
    // Authenticate with JWT
    AuthContext authContext;
    authContext.jwt_token = jwtToken.c_str();
    
    SDKError err = authService->SDKAuth(authContext);
    if (err != SDKERR_SUCCESS) {
        std::wcout << L"SDKAuth failed: " << err << std::endl;
        return false;
    }
    
    // CRITICAL: Add message loop or callback won't fire!
    // See complete example: examples/authentication-pattern.md
    
    return true;
}

AuthServiceEventListener.h:

#include <windows.h>
#include <cstdint>
#include <auth_service_interface.h>
#include <iostream>

using namespace ZOOM_SDK_NAMESPACE;

class AuthServiceEventListener : public IAuthServiceEvent {
public:
    AuthServiceEventListener(void (*onComplete)()) 
        : onAuthComplete(onComplete) {}
    
    void onAuthenticationReturn(AuthResult ret) override {
        if (ret == AUTHRET_SUCCESS && onAuthComplete) {
            onAuthComplete();
        } else {
            std::cout << "Auth failed: " << ret << std::endl;
        }
    }
    
    // Must implement ALL pure virtual methods (6 total)
    void onLoginReturnWithReason(LOGINSTATUS ret, IAccountInfo* info, LoginFailReason reason) override {}
    void onLogout() override {}
    void onZoomIdentityExpired() override {}
    void onZoomAuthIdentityExpired() override {}
#if defined(WIN32)
    void onNotificationServiceStatus(SDKNotificationServiceStatus status, SDKNotificationServiceError error) override {}
#endif

private:
    void (*onAuthComplete)();
};

See complete working code: Authentication Pattern Guide

3. Join Meeting

#include <meeting_service_interface.h>
#include "MeetingServiceEventListener.h"

IMeetingService* meetingService = nullptr;

void OnMeetingJoined() {
    std::cout << "Joining meeting..." << std::endl;
}

void OnInMeeting() {
    std::cout << "In meeting now!" << std::endl;
    // Start raw data capture here
}

void OnMeetingEnds() {
    std::cout << "Meeting ended" << std::endl;
}

bool JoinMeeting(UINT64 meetingNumber, const std::wstring& password) {
    CreateMeetingService(&meetingService);
    if (!meetingService) return false;
    
    // Set event listener
    meetingService->SetEvent(
        new MeetingServiceEventListener(&OnMeetingJoined, &OnMeetingEnds, &OnInMeeting)
    );
    
    // Prepare join parameters
    JoinParam joinParam;
    joinParam.userType = SDK_UT_WITHOUT_LOGIN;
    
    JoinParam4WithoutLogin& params = joinParam.param.withoutloginuserJoin;
    params.meetingNumber = meetingNumber;
    params.userName = L"Bot User";
    params.psw = password.c_str();
    params.isVideoOff = false;
    params.isAudioOff = false;
    
    SDKError err = meetingService->Join(joinParam);
    if (err != SDKERR_SUCCESS) {
        std::wcout << L"Join failed: " << err << std::endl;
        return false;
    }
    return true;
}

MeetingServiceEventListener.h:

#include <windows.h>
#include <cstdint>
#include <meeting_service_interface.h>
#include <iostream>

using namespace ZOOM_SDK_NAMESPACE;

class MeetingServiceEventListener : public IMeetingServiceEvent {
public:
    MeetingServiceEventListener(
        void (*onJoined)(),
        void (*onEnded)(), 
        void (*onInMeeting)()
    ) : onMeetingJoined(onJoined), 
        onMeetingEnded(onEnded),
        onInMeetingCallback(onInMeeting) {}
    
    void onMeetingStatusChanged(MeetingStatus status, int iResult) override {
        if (status == MEETING_STATUS_CONNECTING) {
            if (onMeetingJoined) onMeetingJoined();
        }
        else if (status == MEETING_STATUS_INMEETING) {
            if (onInMeetingCallback) onInMeetingCallback();
        }
        else if (status == MEETING_STATUS_ENDED) {
            if (onMeetingEnded) onMeetingEnded();
        }
    }
    
    // Must implement ALL pure virtual methods (9 total)
    void onMeetingStatisticsWarningNotification(StatisticsWarningType type) override {}
    void onMeetingParameterNotification(const MeetingParameter* param) override {}
    void onSuspendParticipantsActivities() override {}
    void onAICompanionActiveChangeNotice(bool isActive) override {}
    void onMeetingTopicChanged(const zchar_t* sTopic) override {}
    void onMeetingFullToWatchLiveStream(const zchar_t* sLiveStreamUrl) override {}
    void onUserNetworkStatusChanged(MeetingComponentType type, ConnectionQuality level, unsigned int userId, bool uplink) override {}
#if defined(WIN32)
    void onAppSignalPanelUpdated(IMeetingAppSignalHandler* pHandler) override {}
#endif

private:
    void (*onMeetingJoined)();
    void (*onMeetingEnded)();
    void (*onInMeetingCallback)();
};

See all required methods: Interface Methods Guide

4. Subscribe to Raw Video

#include <windows.h>
#include <cstdint>
#include <rawdata/zoom_rawdata_api.h>
#include <rawdata/rawdata_renderer_interface.h>
#include <zoom_sdk_raw_data_def.h>  // REQUIRED for YUVRawDataI420
#include "ZoomSDKRendererDelegate.h"

IZoomSDKRenderer* videoHelper = nullptr;
ZoomSDKRendererDelegate* videoSource = new ZoomSDKRendererDelegate();

bool StartVideoCapture(uint32_t userId) {
    // STEP 1: Start raw recording FIRST (required!)
    IMeetingRecordingController* recordCtrl = 
        meetingService->GetMeetingRecordingController();
    
    SDKError canStart = recordCtrl->CanStartRawRecording();
    if (canStart != SDKERR_SUCCESS) {
        std::cout << "Cannot start recording: " << canStart << std::endl;
        return false;
    }
    
    recordCtrl->StartRawRecording();
    
    // Wait for recording to initialize
    std::this_thread::sleep_for(std::chrono::milliseconds(500));
    
    // STEP 2: Create renderer
    SDKError err = createRenderer(&videoHelper, videoSource);
    if (err != SDKERR_SUCCESS || !videoHelper) {
        std::cout << "createRenderer failed: " << err << std::endl;
        return false;
    }
    
    // STEP 3: Set resolution and subscribe
    videoHelper->setRawDataResolution(ZoomSDKResolution_720P);
    err = videoHelper->subscribe(userId, RAW_DATA_TYPE_VIDEO);
    if (err != SDKERR_SUCCESS) {
        std::cout << "Subscribe failed: " << err << std::endl;
        return false;
    }
    
    std::cout << "Video capture started! Frames arrive in onRawDataFrameReceived()" << std::endl;
    return true;
}

ZoomSDKRendererDelegate.h:

#include <windows.h>
#include <cstdint>
#include <rawdata/rawdata_renderer_interface.h>
#include <zoom_sdk_raw_data_def.h>
#include <fstream>
#include <iostream>

using namespace ZOOM_SDK_NAMESPACE;

class ZoomSDKRendererDelegate : public IZoomSDKRendererDelegate {
public:
    void onRawDataFrameReceived(YUVRawDataI420* data) override {
        if (!data) return;
        
        // YUV420 (I420) format: Y plane + U plane + V plane
        int width = data->GetStreamWidth();
        int height = data->GetStreamHeight();
        
        // Calculate buffer sizes
        // Y = full resolution, U/V = quarter resolution each
        size_t ySize = width * height;
        size_t uvSize = ySize / 4;  // (width/2) * (height/2)
        
        // Total size: width * height * 1.5 bytes
        
        // Save to file (playback: ffplay -f rawvideo -pixel_format yuv420p -video_size 1280x720 output.yuv)
        std::ofstream outputFile("output.yuv", std::ios::binary | std::ios::app);
        outputFile.write(data->GetYBuffer(), ySize);    // Brightness
        outputFile.write(data->GetUBuffer(), uvSize);   // Blue-difference
        outputFile.write(data->GetVBuffer(), uvSize);   // Red-difference
        outputFile.close();
    }
    
    void onRawDataStatusChanged(RawDataStatus status) override {
        std::cout << "Raw data status: " << status << std::endl;
    }
    
    void onRendererBeDestroyed() override {
        std::cout << "Renderer destroyed" << std::endl;
    }
};

Complete video capture guide: Raw Video Capture Guide

5. Subscribe to Raw Audio

#include <rawdata/rawdata_audio_helper_interface.h>

class ZoomSDKAudioRawDataDelegate : public IZoomSDKAudioRawDataDelegate {
public:
    void onMixedAudioRawDataReceived(AudioRawData* data) override {
        // Process PCM audio (mixed from all participants)
        std::ofstream pcmFile("audio.pcm", std::ios::binary | std::ios::app);
        pcmFile.write((char*)data->GetBuffer(), data->GetBufferLen());
        pcmFile.close();
    }
    
    void onOneWayAudioRawDataReceived(AudioRawData* data, uint32_t node_id) override {
        // Process audio from specific participant
    }
};

// Subscribe to audio
IZoomSDKAudioRawDataHelper* audioHelper = GetAudioRawdataHelper();
audioHelper->subscribe(new ZoomSDKAudioRawDataDelegate());

6. Main Message Loop (CRITICAL!)

⚠️ WITHOUT THIS, CALLBACKS WON'T FIRE!

#include <windows.h>
#include <thread>
#include <chrono>

int main() {
    // Initialize COM
    CoInitialize(NULL);
    
    // Load config and initialize
    LoadConfig();
    InitMeetingSDK();
    AuthenticateSDK(sdk_jwt);
    
    // CRITICAL: Windows message loop for SDK callbacks
    // SDK uses Windows message pump to dispatch callbacks
    // Without this, callbacks are queued but NEVER fire!
    MSG msg;
    while (!g_exit) {
        // Process all pending Windows messages
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            if (msg.message == WM_QUIT) {
                g_exit = true;
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        
        // Small sleep to avoid busy-waiting
        std::this_thread::sleep_for(std::chrono::milliseconds(100));
    }
    
    // Cleanup
    CleanSDK();
    CoUninitialize();
    
    return 0;
}

Why message loop is critical: The SDK uses Windows COM/messaging for async callbacks. Without PeekMessage(), the SDK queues messages but they're never retrieved/dispatched, so callbacks never execute.

Symptoms without message loop:

  • Authentication timeout (even with valid JWT)
  • Meeting join timeout
  • No callback events fire
  • Appears like network/auth issue but it's a message loop issue

See detailed explanation: Windows Message Loop Guide

Common Issues & Solutions

IssueSolution
Callbacks don't fire / Auth timeoutAdd Windows message loop → Guide
uint32_t / AudioType errorsFix include order → Guide
Abstract class errorImplement all virtual methods → Guide
How to implement [feature]?Follow universal pattern → Guide
Authentication failsCheck JWT token & error codes → Guide
No video frames receivedCall StartRawRecording() first → Guide

Complete troubleshooting: Common Issues Guide

How to Implement Any Feature

The SDK has 35+ feature controllers (audio, video, chat, recording, participants, screen sharing, breakout rooms, webinars, Q&A, polling, whiteboard, captions, AI companion, etc.).

Universal pattern that works for ALL features:

  1. Get the controller (singleton):

    IMeetingAudioController* audioCtrl = meetingService->GetMeetingAudioController();
    IMeetingChatController* chatCtrl = meetingService->GetMeetingChatController();
    // ... 33 more controllers available
    
  2. Implement event listener (observer pattern):

    class MyAudioListener : public IMeetingAudioCtrlEvent {
        void onUserAudioStatusChange(IList<IUserAudioStatus*>* lst) override {
            // React to audio events
        }
        // ... implement all required methods
    };
    
  3. Register and use:

    audioCtrl->SetEvent(new MyAudioListener());
    audioCtrl->MuteAudio(userId, true);  // Use feature
    

Complete guide with examples: SDK Architecture Pattern

Available Examples

ExampleDescription
SkeletonDemoMinimal join meeting - start here
GetVideoRawDataSubscribe to raw video streams
GetAudioRawDataSubscribe to raw audio streams
SendVideoRawDataSend custom video as virtual camera
SendAudioRawDataSend custom audio as virtual mic
GetShareRawDataCapture screen share content
LocalRecordingLocal MP4 recording
ChatDemoIn-meeting chat functionality
CaptionDemoClosed caption/live transcription
BreakoutDemoBreakout room management

Detailed References

🎯 Core Concepts (START HERE!)

📚 Complete Examples

🔧 Troubleshooting Guides

📖 References

Shortened here. Read the whole file on GitHub.

Signals

GitHub stars
77
Forks
16
Last commit
Sep 2026
Advanced
Catalog kind
skill
Gateway key
zoom-meeting-sdk-windows
Source
github.com/zoom/skills