# Exchange credentials for access token This tutorial shows you how to create and publish a Zoom Event by using the API. You will build a example scenario: a **Q4 company town hall** scheduled for December 15, 2025. Each section includes step-by-step guidance—from authentication through verification—and provides runnable code samples in multiple languages. ## What you will build A published virtual event with registration enabled, ready to share with attendees. ## Time required 15—30 minutes ### Prerequisites - Pro+ Zoom account with Webinars Plus or Events license - OAuth credentials (Client ID and Secret) - see [Zoom's OAuth](/docs/integrations/oauth/) - Required OAuth scope: `zoom_events:write:event` - Basic command line knowledge --- ## The scenario: Q4 company town hall You are organizing a virtual company-wide town hall meeting: - **Event name**: "Q4 Town Hall: Looking Ahead to 2026" - **Date**: December 15, 2025, 2:00 PM EST (7:00 PM UTC) - **Format**: Webinar-style (broadcast mode, up to 100K attendees) - **Access**: Private but unrestricted (anyone with link can register) --- ## Step 1: Get your access token Before making any API calls, you need an OAuth access token. This token authorizes all subsequent requests. ### What this step does Exchanging your OAuth credentials for a temporary access token. ### cURL ```shell curl -X POST https://zoom.us/oauth/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -u "YOUR_CLIENT_ID:YOUR_CLIENT_SECRET" ``` ### Python ```python import requests # Exchange credentials for access token token_url = "https://zoom.us/oauth/token" client_id = "YOUR_CLIENT_ID" client_secret = "YOUR_CLIENT_SECRET" response = requests.post( token_url, data={ "grant_type": "client_credentials" }, auth=(client_id, client_secret) ) token_data = response.json() access_token = token_data["access_token"] print(f"Access token obtained: {access_token[:20]}...") ``` ### JavaScript (Node.js) ```javascript const axios = require("axios"); // Exchange credentials for access token const clientId = "YOUR_CLIENT_ID"; const clientSecret = "YOUR_CLIENT_SECRET"; const tokenUrl = "https://zoom.us/oauth/token"; async function getAccessToken() { const response = await axios.post( tokenUrl, "grant_type=client_credentials", { auth: { username: clientId, password: clientSecret, }, headers: { "Content-Type": "application/x-www-form-urlencoded", }, }, ); const accessToken = response.data.access_token; console.log(`Access token obtained: ${accessToken.substring(0, 20)}...`); return accessToken; } const token = await getAccessToken(); ``` ### Results - Zoom validates your credentials. - Returns an access token (valid for ~1 hour). - You will use this token in the `Authorization` header for all API calls. **Save this token** - It is required for later steps. --- ## Step 2: Get your Hub ID Every Webinars Plus & Events account has at least one "hub" - a container for your events. You need the hub ID to create events. ### What this step does Retrieving the list of hubs you have access to and selecting one. ### cURL ```shell # Replace YOUR_ACCESS_TOKEN with the token from Step 1 curl https://api.zoom.us/v2/zoom_events/hubs?role_type=host \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` ### Python ```python import requests # Get list of hubs hub_url = "https://api.zoom.us/v2/zoom_events/hubs" headers = { "Authorization": f"Bearer {access_token}" } params = { "role_type": "host" } response = requests.get(hub_url, headers=headers, params=params) hubs_data = response.json() # Extract the first hub ID hub_id = hubs_data["hubs"][0]["hub_id"] print(f"Using hub ID: {hub_id}") ``` ### JavaScript (Node.js) ```javascript // Get list of hubs async function getHubId(token) { const hubUrl = "https://api.zoom.us/v2/zoom_events/hubs"; const response = await axios.get(hubUrl, { headers: { Authorization: `Bearer ${token}`, }, params: { role_type: "host", }, }); // Extract the first hub ID const hubId = response.data.hubs[0].hub_id; console.log(`Using hub ID: ${hubId}`); return hubId; } const hubId = await getHubId(token); ``` ### Example response ```json { "total_records": 1, "hubs": [ { "hub_id": "dKj3xR9bQYq5mNp8wA7cZf", "name": "Acme Corp Events Hub" } ] } ``` ### Results - Zoom returns all hubs where you are a host. - Most accounts have one default hub. - The `hub_id` will be used in the next step to create your event. **Copy the hub_id** - Create your event. --- ## Step 3: Create the event in draft status Create the event in **draft** status. This allows you to configure everything before making it public. ### What this step does Creating a new event with basic configuration. The event starts in draft mode so you can review before publishing. ### cURL ```shell # Create event (replace YOUR_ACCESS_TOKEN and YOUR_HUB_ID) curl -X POST https://api.zoom.us/v2/zoom_events/events \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "hub_id": "YOUR_HUB_ID", "name": "Q4 Town Hall: Looking Ahead to 2026", "timezone": "America/New_York", "event_type": "SIMPLE_EVENT", "access_level": "PRIVATE_UNRESTRICTED", "meeting_type": "WEBINAR", "attendance_type": "VIRTUAL", "calendar": [ { "start_time": "2025-12-15T19:00:00Z", "end_time": "2025-12-15T20:30:00Z" } ] }' ``` ### Python ```python import requests from datetime import datetime, timezone # Create event event_url = "https://api.zoom.us/v2/zoom_events/events" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } # Event date: December 15, 2025, 2:00 PM EST (7:00 PM UTC) start_time = datetime(2025, 12, 15, 19, 0, 0, tzinfo=timezone.utc) end_time = datetime(2025, 12, 15, 20, 30, 0, tzinfo=timezone.utc) event_data = { "hub_id": hub_id, # From Step 2 "name": "Q4 Town Hall: Looking Ahead to 2026", "timezone": "America/New_York", "event_type": "SIMPLE_EVENT", "access_level": "PRIVATE_UNRESTRICTED", "meeting_type": "WEBINAR", "attendance_type": "VIRTUAL", "calendar": [ { "start_time": start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), "end_time": end_time.strftime("%Y-%m-%dT%H:%M:%SZ") } ] } response = requests.post(event_url, headers=headers, json=event_data) response.raise_for_status() # Check for HTTP errors event_response = response.json() # Save the event ID for next steps event_id = event_response["event_id"] event_url_link = event_response["event_url"] print(f"Event created successfully") print(f"Event ID: {event_id}") print(f"Status: {event_response['status']}") print(f"Registration URL: {event_url_link}") ``` ### JavaScript (Node.js) ```javascript // Create event async function createEvent(token, hubId) { const eventUrl = "https://api.zoom.us/v2/zoom_events/events"; // Event date: December 15, 2025, 2:00 PM EST (7:00 PM UTC) const startTime = new Date("2025-12-15T19:00:00Z"); const endTime = new Date("2025-12-15T20:30:00Z"); const eventData = { hub_id: hubId, // From Step 2 name: "Q4 Town Hall: Looking Ahead to 2026", timezone: "America/New_York", event_type: "SIMPLE_EVENT", access_level: "PRIVATE_UNRESTRICTED", meeting_type: "WEBINAR", attendance_type: "VIRTUAL", calendar: [ { start_time: startTime.toISOString(), end_time: endTime.toISOString(), }, ], }; try { const response = await axios.post(eventUrl, eventData, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); const eventId = response.data.event_id; const eventUrlLink = response.data.event_url; console.log("Event created successfully"); console.log(`Event ID: ${eventId}`); console.log(`Status: ${response.data.status}`); console.log(`Registration URL: ${eventUrlLink}`); return { eventId, eventUrlLink }; } catch (error) { console.error( "Failed to create event:", error.response?.data || error.message, ); throw error; } } const { eventId, eventUrlLink } = await createEvent(token, hubId); ``` ### Example response ```json { "event_id": "kNqLPC6hSFiZ9NpgjA549w", "name": "Q4 Town Hall: Looking Ahead to 2026", "timezone": "America/New_York", "event_type": "SIMPLE_EVENT", "access_level": "PRIVATE_UNRESTRICTED", "meeting_type": "WEBINAR", "attendance_type": "VIRTUAL", "status": "draft", "hub_id": "dKj3xR9bQYq5mNp8wA7cZf", "event_url": "https://events.zoom.us/event/kNqLPC6hSFiZ9NpgjA549w" } ``` ### Results - Zoom creates a new event in draft status. - Returns an `event_id` (this is critical - save it). - Returns an `event_url` (the registration page link). - Event not visible to public yet (still in draft). ### Understanding the fields | Field | Value Used | Why | | ----------------- | ---------------------- | -------------------------------------------------- | | `hub_id` | From Step 2 | Required container for the event | | `event_type` | `SIMPLE_EVENT` | Single-session event (vs multi-session conference) | | `access_level` | `PRIVATE_UNRESTRICTED` | Anyone with link can register | | `meeting_type` | `WEBINAR` | Broadcast mode (100K capacity vs 1K for MEETING) | | `attendance_type` | `VIRTUAL` | Online only (vs IN-PERSON or HYBRID) | **Save the event_id** - It is required for later steps. --- ## Step 4: Verify the event Before publishing, verify the event was created correctly and review its current configuration. ### What this step does Retrieving the event details to confirm all settings are correct. ### cURL ```shell # Verify event (replace YOUR_ACCESS_TOKEN and YOUR_EVENT_ID) curl https://api.zoom.us/v2/zoom_events/events/YOUR_EVENT_ID \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" ``` ### Python ```python import requests # Verify event details verify_url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}" headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(verify_url, headers=headers) response.raise_for_status() # Check for HTTP errors event_details = response.json() # Check critical fields print("Event Verification:") print(f" Name: {event_details['name']}") print(f" Status: {event_details['status']}") # Should be draft print(f" Event ID: {event_details['event_id']}") print(f" Event URL: {event_details['event_url']}") print(f" Meeting Type: {event_details['meeting_type']}") print(f" Access Level: {event_details['access_level']}") # Verification checks assert event_details['status'] == 'draft', "Event should be in draft status" assert event_details['event_id'] == event_id, "Event ID should match" print("\n✓ Event verified successfully") ``` ### JavaScript (Node.js) ```javascript // Verify event details async function verifyEvent(token, eventId) { const verifyUrl = `https://api.zoom.us/v2/zoom_events/events/${eventId}`; const response = await axios.get(verifyUrl, { headers: { Authorization: `Bearer ${token}`, }, }); const eventDetails = response.data; // Check critical fields console.log("Event Verification:"); console.log(` Name: ${eventDetails.name}`); console.log(` Status: ${eventDetails.status}`); // Should be draft console.log(` Event ID: ${eventDetails.event_id}`); console.log(` Event URL: ${eventDetails.event_url}`); console.log(` Meeting Type: ${eventDetails.meeting_type}`); console.log(` Access Level: ${eventDetails.access_level}`); // Verification checks if (eventDetails.status == "draft") { throw new Error("Event should be in draft status"); } if (eventDetails.event_id == eventId) { throw new Error("Event ID should match"); } console.log("\n✓ Event verified successfully"); return eventDetails; } await verifyEvent(token, eventId); ``` ### Results - Zoom returns complete event details. - Verify the status is in `draft`. - All your configuration fields are preserved. - The event is not yet visible to the public. ### Verification checklist - Status is `draft` - Event ID matches what you saved - Event URL is present - Name is correct - Meeting type is `WEBINAR` --- ## Step 5: Publish the event Now that you have verified everything looks correct, publish the event to make it live and accessible to attendees. ### What this step does Changing the event status from draft to Published, making it visible and allowing registrations. ### Important After publishing, certain fields become locked and cannot be changed: - `event_type` (cannot change SIMPLE_EVENT to CONFERENCE). - `meeting_type` (cannot change WEBINAR to MEETING). ### cURL ```shell # Publish event (replace YOUR_ACCESS_TOKEN and YOUR_EVENT_ID) curl -X POST https://api.zoom.us/v2/zoom_events/events/YOUR_EVENT_ID/event_actions \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "operation": "publish" }' ``` ### Python ```python import requests # Publish event publish_url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}/event_actions" headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } publish_data = { "operation": "publish" } response = requests.post(publish_url, headers=headers, json=publish_data) response.raise_for_status() # Check for HTTP errors publish_response = response.json() print("Event published successfully") print(f"Status: {publish_response['status']}") print(f"Event ID: {publish_response['event_id']}") print(f"\nYour event is now live") print(f"Share this registration link: {event_url_link}") ``` ### JavaScript (Node.js) ```javascript // Publish event async function publishEvent(token, eventId) { const publishUrl = `https://api.zoom.us/v2/zoom_events/events/${eventId}/event_actions`; const publishData = { operation: "publish", }; try { const response = await axios.post(publishUrl, publishData, { headers: { Authorization: `Bearer ${token}`, "Content-Type": "application/json", }, }); console.log("Event published successfully"); console.log(`Status: ${response.data.status}`); console.log(`Event ID: ${response.data.event_id}`); console.log("\n Your event is now live"); console.log(`Share this registration link: ${eventUrlLink}`); return response.data; } catch (error) { console.error( "Failed to publish event:", error.response?.data || error.message, ); throw error; } } await publishEvent(token, eventId); ``` ### Example response ```json { "status": "published", "event_id": "kNqLPC6hSFiZ9NpgjA549w" } ``` ### Results - Event status changes from `draft` to `Published`. - Registration page becomes publicly accessible. - Attendees can now register via the `event_url`. - Event appears in your hub's event list. - Certain fields are now locked (event_type, meeting_type). --- ## Step 6: Verify publication and test registration Confirm the event is truly live and the registration page is accessible. ### What this step does Verifying the published status and testing that the registration page loads correctly. ### cURL ```shell # Verify published status curl https://api.zoom.us/v2/zoom_events/events/YOUR_EVENT_ID \ -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \ | grep -E '"status"|"event_url"' ``` ### Python ```python import requests import webbrowser # Verify published status verify_url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}" headers = { "Authorization": f"Bearer {access_token}" } response = requests.get(verify_url, headers=headers) response.raise_for_status() # Check for HTTP errors final_event = response.json() print("Final Verification:") print(f" Status: {final_event['status']}") # Should be PUBLISHED print(f" Event URL: {final_event['event_url']}") # Check status is published if final_event['status'] == 'Published': print("\n✓ Event is Published and live") print(f"\nRegistration page: {final_event['event_url']}") # Optional: Open in browser # webbrowser.open(final_event['event_url']) else: print(f"\n✗ Warning: Event status is {final_event['status']}, expected Published") ``` ### JavaScript (Node.js) ```javascript // Verify published status async function verifyPublished(token, eventId, eventUrlLink) { const verifyUrl = `https://api.zoom.us/v2/zoom_events/events/${eventId}`; const response = await axios.get(verifyUrl, { headers: { Authorization: `Bearer ${token}`, }, }); const finalEvent = response.data; console.log("Final Verification:"); console.log(` Status: ${finalEvent.status}`); // Should be Published console.log(` Event URL: ${finalEvent.event_url}`); // Check status is published if (finalEvent.status === "Published") { console.log("\n✓ Event is Published and live"); console.log(`\nRegistration page: ${finalEvent.event_url}`); } else { console.log( `\n✗ Warning: Event status is ${finalEvent.status}, expected Published`, ); } return finalEvent; } await verifyPublished(token, eventId, eventUrlLink); ``` ### Manual test 1. Copy the `event_url` from the response. 2. Open it in your web browser. 3. Verify the registration page with your event name. ### Results - API confirms status is `Published`. - Event URL is accessible without authentication. - Registration page displays event details. - Attendees can start registering. --- ## What you built Congratulations! You have successfully - **Authenticated** with Zoom's OAuth API. - **Retrieved** your hub ID. - **Created** a new event (Q4 Town Hall). - **Verified** the event configuration. - **Published** the event to make it live. - **Confirmed** the registration page is accessible. ### Your event details - **Type**: Single-session virtual event (SIMPLE_EVENT). - **Format**: Webinar (broadcast mode, up to 100K attendees). - **Access**: Private but unrestricted (anyone with link can register). - **Status**: Published and ready for registrations. ### The registration flow 1. Attendees visit the `event_url` you created. 2. They fill out registration form. 3. They receive confirmation email with join link. 4. On event day, they click join link to enter the webinar. --- ## Complete working example Here is the entire workflow in one script for each language: ### Python (complete) ```python import requests import sys def create_and_publish_event(): """Complete workflow: authenticate, create, and publish event""" # Configuration client_id = "YOUR_CLIENT_ID" client_secret = "YOUR_CLIENT_SECRET" print("Step 1: Getting access token...") # Authenticate token_response = requests.post( "https://zoom.us/oauth/token", data={"grant_type": "client_credentials"}, auth=(client_id, client_secret) ) access_token = token_response.json()["access_token"] print(f" Token obtained: {access_token[:20]}...") # Setup headers headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json" } print("\nStep 2: Getting hub ID...") # Get hub ID hub_response = requests.get( "https://api.zoom.us/v2/zoom_events/hubs", headers=headers, params={"role_type": "host"} ) hub_id = hub_response.json()["hubs"][0]["hub_id"] print(f" Using hub ID: {hub_id}") print("\nStep 3: Creating event...") # Create event # Event date: December 15, 2025, 2:00 PM EST (7:00 PM UTC) from datetime import datetime, timezone start_time = datetime(2025, 12, 15, 19, 0, 0, tzinfo=timezone.utc) end_time = datetime(2025, 12, 15, 20, 30, 0, tzinfo=timezone.utc) event_data = { "hub_id": hub_id, "name": "Q4 Town Hall: Looking Ahead to 2026", "timezone": "America/New_York", "event_type": "SIMPLE_EVENT", "access_level": "PRIVATE_UNRESTRICTED", "meeting_type": "WEBINAR", "attendance_type": "VIRTUAL", "calendar": [ { "start_time": start_time.strftime("%Y-%m-%dT%H:%M:%SZ"), "end_time": end_time.strftime("%Y-%m-%dT%H:%M:%SZ") } ] } event_response = requests.post( "https://api.zoom.us/v2/zoom_events/events", headers=headers, json=event_data ) event_response.raise_for_status() # Check for HTTP errors event_result = event_response.json() event_id = event_result["event_id"] event_url = event_result["event_url"] print(f" Event created: {event_id}") print(f" Status: {event_result['status']}") print("\nStep 4: Verifying event...") # Verify event verify_response = requests.get( f"https://api.zoom.us/v2/zoom_events/events/{event_id}", headers=headers ) verify_data = verify_response.json() assert verify_data['status'] == 'draft', "Event should be in draft" print(" Event verified") print("\nStep 5: Publishing event...") # Publish event publish_response = requests.post( f"https://api.zoom.us/v2/zoom_events/events/{event_id}/event_actions", headers=headers, json={"operation": "publish"} ) publish_response.raise_for_status() # Check for HTTP errors publish_data = publish_response.json() print(f" Event published: {publish_data['status']}") print("\nStep 6: Final verification...") # Final verification final_response = requests.get( f"https://api.zoom.us/v2/zoom_events/events/{event_id}", headers=headers ) final_data = final_response.json() if final_data['status'] == 'Published': print(" Event is Published and live") print(f"\n{'='*60}") print("SUCCESS Your event is ready") print(f"{'='*60}") print(f"Event Name: {final_data['name']}") print(f"Event ID: {event_id}") print(f"Registration URL: {event_url}") print(f"\nShare this link with attendees to start collecting registrations") return event_id, event_url else: print(f"✗ Unexpected status: {final_data['status']}") sys.exit(1) if __name__ == "__main__": create_and_publish_event() ``` ### JavaScript (complete) ```javascript const axios = require("axios"); // Configuration const CLIENT_ID = "YOUR_CLIENT_ID"; const CLIENT_SECRET = "YOUR_CLIENT_SECRET"; async function createAndPublishEvent() { try { console.log("Step 1: Getting access token..."); // Authenticate const tokenResponse = await axios.post( "https://zoom.us/oauth/token", "grant_type=client_credentials", { auth: { username: CLIENT_ID, password: CLIENT_SECRET }, headers: { "Content-Type": "application/x-www-form-urlencoded", }, }, ); const accessToken = tokenResponse.data.access_token; console.log(` Token obtained: ${accessToken.substring(0, 20)}...`); // Setup headers const headers = { Authorization: `Bearer ${accessToken}`, "Content-Type": "application/json", }; console.log("\nStep 2: Getting hub ID..."); // Get hub ID const hubResponse = await axios.get( "https://api.zoom.us/v2/zoom_events/hubs", { headers, params: { role_type: "host" } }, ); const hubId = hubResponse.data.hubs[0].hub_id; console.log(` Using hub ID: ${hubId}`); console.log("\nStep 3: Creating event..."); // Create event // Event date: December 15, 2025, 2:00 PM EST (7:00 PM UTC) const startTime = new Date("2025-12-15T19:00:00Z"); const endTime = new Date("2025-12-15T20:30:00Z"); const eventData = { hub_id: hubId, name: "Q4 Town Hall: Looking Ahead to 2026", timezone: "America/New_York", event_type: "SIMPLE_EVENT", access_level: "PRIVATE_UNRESTRICTED", meeting_type: "WEBINAR", attendance_type: "VIRTUAL", calendar: [ { start_time: startTime.toISOString(), end_time: endTime.toISOString(), }, ], }; const eventResponse = await axios.post( "https://api.zoom.us/v2/zoom_events/events", eventData, { headers }, ); const eventId = eventResponse.data.event_id; const eventUrl = eventResponse.data.event_url; console.log(` Event created: ${eventId}`); console.log(` Status: ${eventResponse.data.status}`); console.log("\nStep 4: Verifying event..."); // Verify event const verifyResponse = await axios.get( `https://api.zoom.us/v2/zoom_events/events/${eventId}`, { headers }, ); if (verifyResponse.data.status == "draft") { throw new Error("Event should be in draft status"); } console.log(" Event verified"); console.log("\nStep 5: Publishing event..."); // Publish event const publishResponse = await axios.post( `https://api.zoom.us/v2/zoom_events/events/${eventId}/event_actions`, { operation: "publish" }, { headers }, ); console.log(` Event published: ${publishResponse.data.status}`); console.log("\nStep 6: Final verification..."); // Final verification const finalResponse = await axios.get( `https://api.zoom.us/v2/zoom_events/events/${eventId}`, { headers }, ); if (finalResponse.data.status === "Published") { console.log(" Event is Published and live"); console.log("\n" + "=".repeat(60)); console.log(" SUCCESS Your event is ready"); console.log("=".repeat(60)); console.log(`Event Name: ${finalResponse.data.name}`); console.log(`Event ID: ${eventId}`); console.log(`Registration URL: ${eventUrl}`); console.log( "\nShare this link with attendees to start collecting registrations", ); return { eventId, eventUrl }; } else { throw new Error(`Unexpected status: ${finalResponse.data.status}`); } } catch (error) { console.error("Error:", error.response?.data || error.message); process.exit(1); } } // Run the workflow createAndPublishEvent(); ``` --- ## Common issues and solutions ### Issue: "No permission to create event" (error 26201) #### Cause Your OAuth token doesn't have the required scope or you are using the wrong hub_id. #### Solution - Verify your OAuth app has `zoom_events:write:event` scope. - Confirm the hub_id you are using is correct (from Step 2. - Ensure the account owner granted permission to your OAuth app. ### Issue: "Invalid event ID" (error 1001) #### Cause Typo in the event_id or using an event_id from a different account. #### Solution - Copy the event_id directly from Step 3 response. - Do not manually type the event_id. - Ensure you are using the same access token throughout. ### Issue: "Event not found" (error 2002) #### Cause Event was deleted or never existed. #### Solution - Verify the event_id is correct. - Check if event was accidentally deleted. - Create a new event starting from Step 3. ### Issue: Token expired during workflow #### Cause OAuth tokens expire after ~1 hour. #### Solution - Complete the workflow within one session. - If token expires, re-run Step 1 to get a new token. - Consider implementing token refresh logic in production code. --- ## Key concepts explained ### Event lifecycle states ```plaintext Draft → Published → [LIVE] → Completed ↓ Cancelled (from Published state only) ``` - **DRAFT**: Event is being configured, not visible to public. - **PUBLISHED**: Event is live, registration open, visible on hub. - **CANCELLED**: Event was published but then cancelled .(requires cancellation message if registrants exist). ### Event type comparison | Event Type | Use Case | Session Count | Example | | -------------- | ------------------- | ---------------------------- | ------------------ | | `SIMPLE_EVENT` | Single session | 1 | Town hall, webinar | | `RECURRING` | Repeating series | Multiple (same content) | Weekly training | | `CONFERENCE` | Multi-session event | Multiple (different content) | Annual summit | ### Access levels | Access Level | Who Can Register | Use Case | | ---------------------- | ---------------------------- | ---------------------------- | | `PRIVATE_UNRESTRICTED` | Anyone with link | Internal events, semi-public | | `PRIVATE_RESTRICTED` | Approved domains/emails only | Corporate events | ### Meeting type capacity | Meeting Type | Max Capacity | Mode | Best For | | ------------ | ------------ | --------------------------------- | ------------------------------- | | `WEBINAR` | 100,000 | Broadcast (panelists + attendees) | Large audiences, presentations | | `MEETING` | 1,000 | Collaborative (all participants) | Workshops, interactive sessions |