Files
2026-07-13 12:20:06 +08:00

8.9 KiB

Zoom GraphQL API (Beta)

Flexible data queries with GraphQL as an alternative to REST.

Overview

Zoom GraphQL API provides a single endpoint for querying and mutating Zoom data. Unlike REST APIs with fixed endpoints, GraphQL allows you to request exactly the data you need.

Status: Beta (requires signup)

Key URLs

Resource URL
Playground https://nws.zoom.us/graphql/playground
Beta Signup https://beta.zoom.us/key/GRAPHQL
Endpoint https://api.zoom.us/graphql

GraphQL vs REST

Feature REST API GraphQL API
Endpoints 600+ endpoints Single endpoint
Data fetching Fixed data per endpoint Client specifies exact fields
Multiple resources Multiple requests Single request
Over-fetching Common Eliminated
Schema Optional (OpenAPI) Mandatory, strongly typed
Learning curve Lower Higher

Authentication

Same OAuth 2.0 as REST API:

const headers = {
  'Authorization': `Bearer ${accessToken}`,
  'Content-Type': 'application/json'
};
  • Server-to-Server OAuth supported
  • User-authorized OAuth supported
  • Access tokens valid for 1 hour

Available Entities

Entity Query Mutation
Users
Meetings Partial
Webinars Partial
Chat Channels Partial -
Cloud Recordings -
Dashboards -
Groups Partial -
Reports Partial -

Note: Not all REST endpoints are available in GraphQL yet (beta).

Query Examples

List Users

query ListUsers {
  users(first: 100) {
    edges {
      node {
        id
        firstName
        lastName
        email
        department
        type
        status
      }
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Get User Details

query GetUser($userId: ID!) {
  user(id: $userId) {
    id
    firstName
    lastName
    email
    department
    timezone
    type
    createdAt
    lastLoginTime
  }
}

Variables:

{
  "userId": "user_abc123"
}

List Meetings

query ListMeetings($userId: ID!) {
  user(id: $userId) {
    meetings(first: 50) {
      edges {
        node {
          id
          topic
          type
          startTime
          duration
          timezone
          joinUrl
        }
      }
    }
  }
}

Get Meeting with Participants

query GetMeetingDetails($meetingId: ID!) {
  meeting(id: $meetingId) {
    id
    topic
    type
    startTime
    duration
    host {
      id
      firstName
      lastName
      email
    }
    participants {
      edges {
        node {
          id
          name
          email
          joinTime
          leaveTime
        }
      }
    }
  }
}

Get Recordings

query GetRecordings($userId: ID!, $from: DateTime!, $to: DateTime!) {
  user(id: $userId) {
    recordings(from: $from, to: $to, first: 50) {
      edges {
        node {
          id
          topic
          startTime
          duration
          totalSize
          recordingFiles {
            id
            fileType
            fileSize
            downloadUrl
          }
        }
      }
    }
  }
}

Mutation Examples

Create User

mutation CreateUser($input: UserCreateInput!) {
  createUser(input: $input) {
    id
    email
    firstName
    lastName
    type
  }
}

Variables:

{
  "input": {
    "action": "CUST_CREATE",
    "userInfo": {
      "email": "newuser@example.com",
      "firstName": "John",
      "lastName": "Doe",
      "type": "BASIC"
    }
  }
}

Update User

mutation UpdateUser($userId: ID!, $input: UserUpdateInput!) {
  updateUser(id: $userId, input: $input) {
    id
    firstName
    lastName
    department
  }
}

Variables:

{
  "userId": "user_abc123",
  "input": {
    "firstName": "Jonathan",
    "department": "Engineering"
  }
}

Making Requests

JavaScript/Node.js

async function graphqlQuery(query, variables = {}) {
  const response = await fetch('https://api.zoom.us/graphql', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      query: query,
      variables: variables
    })
  });
  
  const result = await response.json();
  
  if (result.errors) {
    throw new Error(result.errors[0].message);
  }
  
  return result.data;
}

// Usage
const users = await graphqlQuery(`
  query {
    users(first: 10) {
      edges {
        node {
          id
          email
          firstName
          lastName
        }
      }
    }
  }
`);

console.log(users.users.edges);

Python

import requests

def graphql_query(query, variables=None):
    response = requests.post(
        'https://api.zoom.us/graphql',
        headers={
            'Authorization': f'Bearer {access_token}',
            'Content-Type': 'application/json'
        },
        json={
            'query': query,
            'variables': variables or {}
        }
    )
    
    result = response.json()
    
    if 'errors' in result:
        raise Exception(result['errors'][0]['message'])
    
    return result['data']

# Usage
users = graphql_query('''
    query {
        users(first: 10) {
            edges {
                node {
                    id
                    email
                }
            }
        }
    }
''')

cURL

curl -X POST https://api.zoom.us/graphql \
  -H "Authorization: Bearer ${ACCESS_TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query { users(first: 10) { edges { node { id email } } } }"
  }'

Pagination

GraphQL uses cursor-based pagination:

query PaginatedUsers($cursor: String) {
  users(first: 100, after: $cursor) {
    edges {
      node {
        id
        email
      }
      cursor
    }
    pageInfo {
      hasNextPage
      endCursor
    }
  }
}

Fetching all pages:

async function fetchAllUsers() {
  let allUsers = [];
  let cursor = null;
  let hasNextPage = true;
  
  while (hasNextPage) {
    const result = await graphqlQuery(
      `query($cursor: String) {
        users(first: 100, after: $cursor) {
          edges {
            node { id email firstName lastName }
          }
          pageInfo {
            hasNextPage
            endCursor
          }
        }
      }`,
      { cursor }
    );
    
    allUsers.push(...result.users.edges.map(e => e.node));
    hasNextPage = result.users.pageInfo.hasNextPage;
    cursor = result.users.pageInfo.endCursor;
  }
  
  return allUsers;
}

Error Handling

GraphQL always returns HTTP 200. Errors are in the response body:

{
  "data": null,
  "errors": [
    {
      "message": "User not found",
      "locations": [{ "line": 2, "column": 3 }],
      "path": ["user"],
      "extensions": {
        "code": "NOT_FOUND"
      }
    }
  ]
}

Handle errors:

async function safeQuery(query, variables) {
  const response = await fetch('https://api.zoom.us/graphql', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${accessToken}`,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ query, variables })
  });
  
  const result = await response.json();
  
  if (result.errors && result.errors.length > 0) {
    const error = result.errors[0];
    console.error(`GraphQL Error: ${error.message}`);
    console.error(`Code: ${error.extensions?.code}`);
    throw new Error(error.message);
  }
  
  return result.data;
}

When to Use GraphQL vs REST

Use GraphQL When:

  • Fetching specific fields from complex nested data
  • Making multiple related queries in one request
  • Building mobile apps where bandwidth matters
  • Working with interconnected user, meeting, webinar data
  • Prototyping and exploring the API

Use REST When:

  • Need access to all 600+ endpoints (GraphQL coverage incomplete)
  • Building simple CRUD applications
  • Require HTTP caching
  • Team is unfamiliar with GraphQL
  • Production stability is critical (GraphQL is beta)

Playground

The GraphQL Playground at https://nws.zoom.us/graphql/playground provides:

  • Interactive query editor
  • Auto-complete and syntax highlighting
  • Query history
  • Embedded documentation
  • Schema explorer

Note: Requires beta access.

Limitations (Beta)

Limitation Notes
Coverage Not all REST endpoints available
Stability Beta - features may change
Access Requires explicit beta signup
Documentation Less comprehensive than REST

Resources