PHP sample

Zoom API and SDK reference

Runnable PHP examples for Zoom webhooks, Server-to-Server OAuth, OAuth redirects, Meeting SDK signatures, token refresh, and REST API calls.

GitHub source

Live demo

WebhookInspect the last received webhook payload. S2S OAuthRequest an account access token. OAuth redirectExchange an authorization code. Refresh tokenExchange a refresh token with streams. Refresh token curlExchange a refresh token with curl. Meeting SDK FirebaseGenerate a Meeting SDK signature. Meeting SDKGenerate a Meeting SDK signature without Firebase. REST APICreate a sample meeting with an access token. Install URLStart the Zoom OAuth authorization flow.

Code samples

Webhook handler

  

$config = include 'config.php';
$secretToken = $config['webhook_app_secret_token'];

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // This block handles POST requests

    // Get the raw POST data from the request
    $input = file_get_contents("php://input");

    // Decode the JSON data
    $data = json_decode($input);

    // Check if the event type is "endpoint.url_validation"
    if ($data && isset($data->event) && $data->event === "endpoint.url_validation") {
        // Check if the payload contains the "plainToken" property
        if (isset($data->payload) && isset($data->payload->plainToken)) {
            // Get the plainToken from the payload
            $plainToken = $data->payload->plainToken;

            // Hash the plainToken using HMAC-SHA256
            $encryptedToken = hash_hmac("sha256", $plainToken, $secretToken);

            // Create the response JSON object
            $response = [
                "plainToken" => $plainToken,
                "encryptedToken" => $encryptedToken
            ];

            // Set the response HTTP status code to 200 OK
            http_response_code(200);

            // Set the response content type to JSON
            header("Content-Type: application/json");

            // Output the response JSON
            echo json_encode($response);

        } else {
            // Payload is missing the "plainToken" property
            http_response_code(400); // Bad Request
            echo "Payload is missing 'plainToken' property.";
        }
    } else {

        try{
        // Save the JSON data to a file
        $jsonFileName = '/var/www/php.asdc.cc/webhook.txt'; // Set the filename
        file_put_contents($jsonFileName, json_encode($data));
        echo "Data Saved: " .  json_encode($data);
        }
        catch(Exception $e){
            echo "An error occurred: " . $e->getMessage();
        }
    }
} elseif ($_SERVER['REQUEST_METHOD'] === 'GET') {
    // This block handles GET requests

    $jsonFileName = '/var/www/php.asdc.cc/webhook.txt'; 
    // Check if the file 'token.txt' exists
    if (file_exists('/var/www/php.asdc.cc/webhook.txt')) {
        try{
         // Read the JSON data from the file
         $jsonContents = file_get_contents($jsonFileName);

        // Parse the JSON data into a PHP object
        $jsonData = json_decode($jsonContents);

        // Convert the PHP object back to a JSON string
        $jsonString = json_encode($jsonData);

        // Echo the JSON string
        echo $jsonString;
        }
        catch(Exception $e){
            echo "An error occurred: " . $e->getMessage();
        }
    } else {
        // Token file does not exist
        echo "Token file does not exist.";
    }
} else {
    // Unsupported HTTP method
    http_response_code(405); // Method Not Allowed
    echo "Unsupported HTTP method.";
}


Server-to-Server OAuth token

  
$config = include 'config.php';


// Access the environment variables
$clientId  = $config['s2s_oauth_client_id'];
$clientSecret  = $config['s2s_oauth_client_secret'];
$accountId= $config['s2s_oauth_account_id'];
$oauthUrl = 'https://zoom.us/oauth/token?grant_type=account_credentials&account_id=' . $accountId;  // Replace with your OAuth endpoint URL


    global $clientSecret, $clientId, $oauthUrl;


    try {
        // Create the Basic Authentication header
        $authHeader = 'Basic ' . base64_encode($clientId . ':' . $clientSecret);
     
        // Initialize cURL session
        $ch = curl_init($oauthUrl);

        // Set cURL options
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Authorization: ' . $authHeader));

        // Execute cURL session and get the response
        $response = curl_exec($ch);

        // Check if the request was successful (status code 200)
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        if ($httpCode == 200) {
            // Parse the JSON response to get the access token
            $oauthResponse = json_decode($response, true);
            $accessToken = $oauthResponse['access_token'];
            //return $accessToken;
            http_response_code(200); // Replace 200 with your desired status code
            // Set the "Content-Type" header to "application/json"
            header('Content-Type: application/json');
            echo json_encode($accessToken);
      
            
        } else {
            echo 'OAuth Request Failed with Status Code: ' . $httpCode . PHP_EOL;
            echo $response . PHP_EOL;
            return null;
        }

        // Close cURL session
        curl_close($ch);
    } catch (Exception $e) {
        echo 'An error occurred: ' . $e->getMessage() . PHP_EOL;
        return null;
    }

    
    

OAuth redirect exchange

 
$config = include 'config.php';
$oauthClientId = $config['oauth_client_id'];
$oauthClientSecret = $config['oauth_client_secret'];


$path='redirecturlforoauth.php';
$code =$_GET['code'];


    //echo "handleRedirectUrlDataRequest\n";
    $url = "https://zoom.us/oauth/token";
    $redirectUri = "https://php.asdc.cc/$path";
    //echo "$redirectUri\n";
    
    // Encode the client ID and client secret
    $credentials = "$oauthClientId:$oauthClientSecret";
    //echo "$credentials\n";
    $credentialsEncoded = base64_encode($credentials);

    $headers = [
        "Authorization: Basic $credentialsEncoded",
        "Content-Type: application/x-www-form-urlencoded"
    ];
    //echo "$credentialsEncoded\n";

    $data = [
        'grant_type' => 'authorization_code',
        'redirect_uri' => $redirectUri,
        'code' => $code
    ];
     //echo "$data\n";
    // Encode the data dictionary as x-www-form-urlencoded
    $dataEncoded = http_build_query($data);
    //echo "$dataEncoded\n";
    $options = [
        'http' => [
            'header' => implode("\r\n", $headers),
            'method' => 'POST',
            'content' => $dataEncoded
        ]
    ];
    $context = stream_context_create($options);
   
    $response = file_get_contents($url, false, $context);
    
    $httpStatus = $http_response_header[0]; // Get the HTTP status from the headers

    if (strpos($httpStatus, '200 OK') !== false) {
        //echo "response 200\n";
        $responseJson = json_decode($response, true); // Decode JSON as associative array
        
        // Optionally, you can return an HTTP status code
        http_response_code(200); // Replace 200 with your desired status code
        
        // Set the "Content-Type" header to "application/json"
        header('Content-Type: application/json');

        // Encode the JSON data and return it
        echo json_encode($responseJson);

   
    } else {
        // Handle the case where the response has an error status code
        echo "$httpStatus\n";
    }




Meeting SDK signature with Firebase JWT

  
// Step 1: Include Composer's autoload.php
require 'vendor/autoload.php';

// Step 2: Import the Firebase JWT class
use Firebase\JWT\JWT;


$config = include 'config.php';
$meetingSDKClientKey=$config['meetingSDKClientKey'];
$meetingSDKClientSecret= $config['meetingSDKClientSecret'];


$iat = time();
$exp = $iat + 60 * 60 * 2;
$token_payload = [

    'sdkKey' => $meetingSDKClientKey,
    'mn' => 9898533313,
    'role' => 1,
    'iat' => $iat,
    'exp' => $exp,
    'tokenExp' => $exp
];

$jwt = JWT::encode($token_payload, $meetingSDKClientSecret, 'HS256');
echo $jwt;

Meeting SDK signature

  
$config = include 'config.php';
$meetingSDKClientKey = $config['meetingSDKClientKey'];
$meetingSDKClientSecret = $config['meetingSDKClientSecret'];


$iat = time()    - 30;
$exp = $iat + 60 * 60 * 10;
//$client_request = $this->request->input('json_decode');

// Define the payload data for your JWT token
$token_payload = [
    'sdkKey' => $meetingSDKClientKey,
    'mn' => 9898533313,
    'role' => 1,
    'iat' => $iat, // Issued at timestamp
    'exp' => $exp,  // Expiration timestamp (2 hours from now)
    'appKey' => $meetingSDKClientKey,
    'tokenExp' => $exp 
];

// Encode the JWT token
$header = json_encode(['typ' => 'JWT', 'alg' => 'HS256']);
$payload = json_encode($token_payload);

$headers_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));
$payload_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));

$signature = hash_hmac('sha256', $headers_encoded . '.' . $payload_encoded, $meetingSDKClientSecret, true);
$signature_encoded = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

$jwt = $headers_encoded . '.' . $payload_encoded . '.' . $signature_encoded;

echo $jwt;


OAuth refresh token

  
$config = include 'config.php';
$oauthClientId=$config['oauth_client_id'];
$oauthClientSecret= $config['oauth_client_secret'];
$refreshToken=$_GET['code'];



    $url = 'https://zoom.us/oauth/token';


    // Encode the client ID and client secret
    $credentials = "$oauthClientId:$oauthClientSecret";
   
    $credentialsEncoded = base64_encode($credentials);

    $headers = [
        "Authorization: Basic $credentialsEncoded",
        "Content-Type: application/x-www-form-urlencoded"
    ];
  

    $data = [
        'grant_type' => 'refresh_token',
        'refresh_token' => $refreshToken,
    ];
   
    // Encode the data dictionary as x-www-form-urlencoded
    $dataEncoded = http_build_query($data);
    
    $options = [
        'http' => [
            'header' => implode("\r\n", $headers),
            'method' => 'POST',
            'content' => $dataEncoded
        ]
    ];
    $context = stream_context_create($options);
   
    $response = file_get_contents($url, false, $context);
    
    $httpStatus = $http_response_header[0]; // Get the HTTP status from the headers

    if (strpos($httpStatus, '200 OK') !== false) {
        //echo "response 200\n";
        $responseJson = json_decode($response, true); // Decode JSON as associative array
        
        // Optionally, you can return an HTTP status code
        http_response_code(200); // Replace 200 with your desired status code
        
        // Set the "Content-Type" header to "application/json"
        header('Content-Type: application/json');

        // Encode the JSON data and return it
        echo json_encode($responseJson);

   
    } else {
        // Handle the case where the response has an error status code
        echo "$httpStatus\n";
    }
    

OAuth refresh token with curl

  
$config = include 'config.php';
$oauthClientId=$config['oauth_client_id'];
$oauthClientSecret= $config['oauth_client_secret'];
$refreshToken=$_GET['code'];



$url = 'https://zoom.us/oauth/token';

// Encode the client ID and client secret
$basic = base64_encode($oauthClientId . ':' . $oauthClientSecret);

$headers = [
    "Authorization: Basic $basic",
    "Content-Type: application/x-www-form-urlencoded"
];

$data = [
    'grant_type' => 'refresh_token',
    'refresh_token' => $refreshToken,
];

// Encode the data dictionary as x-www-form-urlencoded
$dataEncoded = http_build_query($data);

$options = [
    CURLOPT_URL => $url,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_CUSTOMREQUEST => 'POST',
    CURLOPT_HTTPHEADER => $headers,
    CURLOPT_POSTFIELDS => $dataEncoded,
];

$ch = curl_init();
curl_setopt_array($ch, $options);

$response = curl_exec($ch);
$httpStatus = curl_getinfo($ch, CURLINFO_HTTP_CODE);

curl_close($ch);

if (strpos($httpStatus, '200') !== false) {
    $responseJson = json_decode($response, true);
    http_response_code(200);
    header('Content-Type: application/json');
    echo json_encode($responseJson);
    //echo $response;
} else {
    echo "$httpStatus\n";
}


REST API call

  
$access_token = $_GET['accesstoken'] ?? '';
if ($access_token === '' || $access_token === 'xxxx') {
    http_response_code(400);
    header('Content-Type: application/json');
    echo json_encode(['message' => 'Add ?accesstoken=your_token to call the API']);
    exit;
}

$meeting_data = [
    "topic" =>  'hello world',
    "type" => 2,
    "start_time" => gmdate('Y-m-d\TH:i:s\Z', time() + 3600),
    "duration" =>  120,
    "password" => "12345678",
    "agenda" => "40 mins limit demonstration",
    "pre_schedule" => false,
    "timezone"=> "Asia/Singapore",
    "default_password" => false
];

$api_url = 'https://api.zoom.us/v2/users/me/meetings';
$ch_meeting = curl_init($api_url );


curl_setopt($ch_meeting, CURLOPT_HTTPHEADER, array(
  "Authorization: Bearer $access_token",
  'Content-Type: application/json',
  'Accept: application/json'
));

curl_setopt($ch_meeting, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch_meeting, CURLOPT_POSTFIELDS, json_encode($meeting_data));
curl_setopt($ch_meeting, CURLOPT_RETURNTRANSFER, true);

    $meeting_response = curl_exec($ch_meeting);
    echo "Meeting Details : ";
    echo $meeting_response;