Extract the first hub ID
What you will build
In this tutorial, you will create a complete single-session virtual event for "CloudSync Pro Launch" a product unveiling webinar scheduled for December 15, 2025, at 2:00 PM EST. You will set up registration, configure branding, pre-register VIP attendees, and publish the event to make it live.
Event Details
- Product: CloudSync Pro - Next-generation cloud storage solution
- Date: December 15, 2025, 2:00 PM - 3:00 PM EST
- Format: Virtual webinar (up to 10,000 attendees)
- Registration: Public with email confirmation
- Duration: 1 hour live presentation + Q&A
Time required
20—30 minutes
What you will learn
- Create a SIMPLEEVENT (_single-session) event.
- Configure webinar-style presentation settings.
- Set up public registration with authentication.
- Pre-register VIP attendees via API.
- Publish and activate your event.
Prerequisites
Before starting, ensure you have:
- Account: Zoom Pro or higher account plan
- License: Zoom Webinars Plus or Events license
- API Access: Server-to-Server OAuth app or OAuth app with these scopes:
zoom_events:write:event(orzoom_events_basic:write:admin)zoom_events:write:access_links(orzoom_events_access_links:write:admin)zoom_events:write:ticket(orzoom_events_tickets:write:admin)
- Access Token: Valid OAuth access token (referenced as
YOUR_ACCESS_TOKENbelow)
No API credentials? Visit the Zoom Marketplace to create an app.
Step 1: Get your Hub ID
Every Zoom Events event must belong to an event hub. Retrieve your hub ID.
cURL
curl -X GET "https://api.zoom.us/v2/zoom_events/hubs?role_type=host" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Python
import requests
url = "https://api.zoom.us/v2/zoom_events/hubs"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
params = {
"role_type": "host"
}
response = requests.get(url, headers=headers, params=params)
response.raise_for_status() # Check for HTTP errors
hubs = response.json()
# Extract the first hub ID
hub_id = hubs["hubs"][0]["hub_id"]
print(f"Hub ID: {hub_id}")
JavaScript (Node.js)
const axios = require("axios");
async function getHubId() {
const url = "https://api.zoom.us/v2/zoom_events/hubs";
const headers = {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
const params = {
role_type: "host",
};
try {
const response = await axios.get(url, { headers, params });
const hubId = response.data.hubs[0].hub_id;
console.log(`Hub ID: ${hubId}`);
return hubId;
} catch (error) {
console.error(
"Failed to get hub ID:",
error.response?.data || error.message,
);
throw error;
}
}
getHubId();
Expected Response
{
"total_records": 1,
"hubs": [
{
"hub_id": "aBcDeFgH1234567890",
"name": "My Events Hub",
"hub_active": true
}
]
}
Save this hub_id - You will need it in the next step.
Step 2: Create the product launch event
Create the CloudSync Pro Launch event as a single-session webinar.
cURL
curl -X POST "https://api.zoom.us/v2/zoom_events/events" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"hub_id": "aBcDeFgH1234567890",
"name": "CloudSync Pro Launch",
"": "Join us for the exclusive launch of CloudSync Pro, our next-generation cloud storage solution. Discover breakthrough features, live demos, and special launch pricing available only to attendees.",
"timezone": "America/New_York",
"event_type": "SIMPLE_EVENT",
"access_level": "PRIVATE_UNRESTRICTED",
"meeting_type": "WEBINAR",
"attendance_type": "VIRTUAL",
"tagline": "The Future of Cloud Storage Starts Here",
"contact_name": "Sarah Chen",
"calendar": [
{
"start_time": "2025-12-15T19:00:00Z",
"end_time": "2025-12-15T20:00:00Z"
}
]
}'
Python
import requests
from datetime import datetime, timezone
url = "https://api.zoom.us/v2/zoom_events/events"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
event_data = {
"hub_id": "aBcDeFgH1234567890",
"name": "CloudSync Pro Launch",
"": "Join us for the exclusive launch of CloudSync Pro, our next-generation cloud storage solution. Discover breakthrough features, live demos, and special launch pricing available only to attendees.",
"timezone": "America/New_York",
"event_type": "SIMPLE_EVENT",
"access_level": "PRIVATE_UNRESTRICTED",
"meeting_type": "WEBINAR",
"attendance_type": "VIRTUAL",
"tagline": "The Future of Cloud Storage Starts Here",
"contact_name": "Sarah Chen",
"calendar": [
{
"start_time": "2025-12-15T19:00:00Z", # 2 PM EST = 7 PM UTC
"end_time": "2025-12-15T20:00:00Z" # 3 PM EST = 8 PM UTC
}
]
}
response = requests.post(url, headers=headers, json=event_data)
response.raise_for_status() # Check for HTTP errors
event = response.json()
event_id = event["event_id"]
print(f"Event created. Event ID: {event_id}")
print(f"Status: {event['status']}")
JavaScript (Node.js)
const axios = require('axios');
async function createEvent(hubId) {
const url = 'https://api.zoom.us/v2/zoom_events/events';
const headers = {
'Content-Type': 'application/json',
'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
};
const eventData = {
hub_id: hubId,
name: 'CloudSync Pro Launch',
: 'Join us for the exclusive launch of CloudSync Pro, our next-generation cloud storage solution. Discover breakthrough features, live demos, and special launch pricing available only to attendees.',
timezone: 'America/New_York',
event_type: 'SIMPLE_EVENT',
access_level: 'PRIVATE_UNRESTRICTED',
meeting_type: 'WEBINAR',
attendance_type: 'VIRTUAL',
tagline: 'The Future of Cloud Storage Starts Here',
contact_name: 'Sarah Chen',
calendar: [
{
start_time: '2025-12-15T19:00:00Z', // 2 PM EST = 7 PM UTC
end_time: '2025-12-15T20:00:00Z' // 3 PM EST = 8 PM UTC
}
]
};
try {
const response = await axios.post(url, eventData, { headers });
const event = response.data;
console.log(`Event created. Event ID: ${event.event_id}`);
console.log(`Status: ${event.status}`);
return event.event_id;
} catch (error) {
console.error('Failed to create event:', error.response?.data || error.message);
throw error;
}
}
createEvent('aBcDeFgH1234567890');
Expected Response
{
"event_id": "kNqLPC6hSFiZ9NpgjA549w",
"name": "CloudSync Pro Launch",
"": "Join us for the exclusive launch of CloudSync Pro...",
"timezone": "America/New_York",
"event_type": "SIMPLE_EVENT",
"status": "draft",
"meeting_type": "WEBINAR",
"access_level": "PRIVATE_UNRESTRICTED",
"attendance_type": "VIRTUAL",
"hub_id": "aBcDeFgH1234567890",
"calendar": [
{
"start_time": "2025-12-15T19:00:00Z",
"end_time": "2025-12-15T20:00:00Z"
}
],
"tagline": "The Future of Cloud Storage Starts Here",
"contact_name": "Sarah Chen"
}
Important Notes
- The event starts in draft status (not yet live)
event_type: "SIMPLE_EVENT"is immutable - cannot be changed after creation.meeting_type: "WEBINAR"supports up to 100,000 attendees (host/panelist video only).- Times must be in UTC format (
yyyy-MM-ddTHH:mm:ssZ).
Save the event_id - You will use it throughout the rest of the tutorial.
Step 3: Retrieve the default Ticket Type
Zoom Events automatically creates a "General Admission" ticket type when you create an event. Retrieve its ID.
cURL
curl -X GET "https://api.zoom.us/v2/zoom_events/events/kNqLPC6hSFiZ9NpgjA549w/ticket_types" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Python
import requests
event_id = "kNqLPC6hSFiZ9NpgjA549w"
url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}/ticket_types"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
response = requests.get(url, headers=headers)
response.raise_for_status() # Check for HTTP errors
ticket_types = response.json()
# Get the first (default) ticket type
ticket_type_id = ticket_types["ticket_types"][0]["ticket_type_id"]
print(f"Ticket Type ID: {ticket_type_id}")
print(f"Name: {ticket_types['ticket_types'][0]['name']}")
JavaScript (Node.js)
const axios = require("axios");
async function getTicketTypeId(eventId) {
const url = `https://api.zoom.us/v2/zoom_events/events/${eventId}/ticket_types`;
const headers = {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
try {
const response = await axios.get(url, { headers });
const ticketTypeId = response.data.ticket_types[0].ticket_type_id;
console.log(`Ticket Type ID: ${ticketTypeId}`);
console.log(`Name: ${response.data.ticket_types[0].name}`);
return ticketTypeId;
} catch (error) {
console.error(
"Failed to get ticket type:",
error.response?.data || error.message,
);
throw error;
}
}
getTicketTypeId("kNqLPC6hSFiZ9NpgjA549w");
Expected Response
{
"total_records": 1,
"ticket_types": [
{
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"name": "General Admission",
"currency": "USD",
"free": true,
"price": "0",
"quantity": 50
}
]
}
Save the ticket_type_id - You will use it when creating registration links and tickets.
Step 4: Create a public registration link
Create a registration link that anyone can use to sign up for the CloudSync Pro Launch.
cURL
curl -X POST "https://api.zoom.us/v2/zoom_events/events/kNqLPC6hSFiZ9NpgjA549w/access_links" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"name": "Public Registration",
"type": "registration",
"is_default": true,
"authentication_method": "bypass_auth",
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"security_at_join": {
"email_authentication": false,
"security_code_verification": false
}
}'
Python
import requests
event_id = "kNqLPC6hSFiZ9NpgjA549w"
ticket_type_id = "234kjhg23kl4jhlaksjdh3"
url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}/access_links"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
link_data = {
"name": "Public Registration",
"type": "registration",
"is_default": True,
"authentication_method": "bypass_auth",
"ticket_type_id": ticket_type_id,
"security_at_join": {
"email_authentication": False,
"security_code_verification": False
}
}
response = requests.post(url, headers=headers, json=link_data)
response.raise_for_status() # Check for HTTP errors
access_link = response.json()
print(f"Registration link created")
print(f"Link ID: {access_link['access_link_id']}")
print(f"Type: {access_link['type']}")
JavaScript (Node.js)
const axios = require("axios");
async function createRegistrationLink(eventId, ticketTypeId) {
const url = `https://api.zoom.us/v2/zoom_events/events/${eventId}/access_links`;
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
const linkData = {
name: "Public Registration",
type: "registration",
is_default: true,
authentication_method: "bypass_auth",
ticket_type_id: ticketTypeId,
security_at_join: {
email_authentication: false,
security_code_verification: false,
},
};
try {
const response = await axios.post(url, linkData, { headers });
const accessLink = response.data;
console.log("Registration link created");
console.log(`Link ID: ${accessLink.access_link_id}`);
console.log(`Type: ${accessLink.type}`);
return accessLink.access_link_id;
} catch (error) {
console.error(
"Failed to create registration link:",
error.response?.data || error.message,
);
throw error;
}
}
createRegistrationLink("kNqLPC6hSFiZ9NpgjA549w", "234kjhg23kl4jhlaksjdh3");
Expected response
{
"access_link_id": "xyz789abc456",
"name": "Public Registration",
"type": "registration",
"is_default": true,
"authentication_method": "bypass_auth",
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"security_at_join": {
"email_authentication": false,
"security_code_verification": false
}
}
What this does
type: "registration"- Attendees must register before joining.authentication_method: "bypass_auth"- No login required (public event).is_default: true- This link is the primary registration path.security_at_join.email_authentication: false- No email authentication required at join time.security_at_join.security_code_verification: false- No security code required at join time.
Alternative authentication methods
zoom_account- Require Zoom account sign-inzoom_account_otp- Zoom account or email OTPcorporate_idp- Enterprise SSO (single sign-on)
Step 5: Pre-register VIP attendees (optional)
For the CloudSync Pro Launch, pre-register three VIP guests who should receive direct invitations.
cURL
curl -X POST "https://api.zoom.us/v2/zoom_events/events/kNqLPC6hSFiZ9NpgjA549w/tickets" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"tickets": [
{
"email": "alex.rivera@techcorp.com",
"first_name": "Alex",
"last_name": "Rivera",
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"send_notification": true,
"fast_join": false
},
{
"email": "jordan.patel@innovate.io",
"first_name": "Jordan",
"last_name": "Patel",
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"send_notification": true,
"fast_join": false
},
{
"email": "taylor.kim@cloudsys.com",
"first_name": "Taylor",
"last_name": "Kim",
"ticket_type_id": "234kjhg23kl4jhlaksjdh3",
"send_notification": true,
"fast_join": false
}
]
}'
Python
import requests
event_id = "kNqLPC6hSFiZ9NpgjA549w"
ticket_type_id = "234kjhg23kl4jhlaksjdh3"
url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}/tickets"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
# VIP attendee list
tickets_data = {
"tickets": [
{
"email": "alex.rivera@techcorp.com",
"first_name": "Alex",
"last_name": "Rivera",
"ticket_type_id": ticket_type_id,
"send_notification": True,
"fast_join": False
},
{
"email": "jordan.patel@innovate.io",
"first_name": "Jordan",
"last_name": "Patel",
"ticket_type_id": ticket_type_id,
"send_notification": True,
"fast_join": False
},
{
"email": "taylor.kim@cloudsys.com",
"first_name": "Taylor",
"last_name": "Kim",
"ticket_type_id": ticket_type_id,
"send_notification": True,
"fast_join": False
}
]
}
response = requests.post(url, headers=headers, json=tickets_data)
response.raise_for_status() # Check for HTTP errors
result = response.json()
print(f"Pre-registered {len(result['tickets'])} VIP attendees")
for ticket in result['tickets']:
print(f" - {ticket['email']}: {ticket.get('event_join_link', 'N/A')}")
JavaScript (Node.js)
const axios = require("axios");
async function preRegisterVIPs(eventId, ticketTypeId) {
const url = `https://api.zoom.us/v2/zoom_events/events/${eventId}/tickets`;
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
const ticketsData = {
tickets: [
{
email: "alex.rivera@techcorp.com",
first_name: "Alex",
last_name: "Rivera",
ticket_type_id: ticketTypeId,
send_notification: true,
fast_join: false,
},
{
email: "jordan.patel@innovate.io",
first_name: "Jordan",
last_name: "Patel",
ticket_type_id: ticketTypeId,
send_notification: true,
fast_join: false,
},
{
email: "taylor.kim@cloudsys.com",
first_name: "Taylor",
last_name: "Kim",
ticket_type_id: ticketTypeId,
send_notification: true,
fast_join: false,
},
],
};
try {
const response = await axios.post(url, ticketsData, { headers });
const result = response.data;
console.log(`Pre-registered ${result.tickets.length} VIP attendees`);
result.tickets.forEach((ticket) => {
console.log(
` - ${ticket.email}: ${ticket.event_join_link || "N/A"}`,
);
});
} catch (error) {
console.error(
"Failed to pre-register VIPs:",
error.response?.data || error.message,
);
throw error;
}
}
preRegisterVIPs("kNqLPC6hSFiZ9NpgjA549w", "234kjhg23kl4jhlaksjdh3");
Expected response
{
"errors": [],
"tickets": [
{
"ticket_id": "ticket_abc123",
"email": "alex.rivera@techcorp.com",
"first_name": "Alex",
"last_name": "Rivera",
"event_join_link": "https://events.zoom.us/j/xyz123abc"
},
{
"ticket_id": "ticket_def456",
"email": "jordan.patel@innovate.io",
"first_name": "Jordan",
"last_name": "Patel",
"event_join_link": "https://events.zoom.us/j/xyz456def"
},
{
"ticket_id": "ticket_ghi789",
"email": "taylor.kim@cloudsys.com",
"first_name": "Taylor",
"last_name": "Kim",
"event_join_link": "https://events.zoom.us/j/xyz789ghi"
}
]
}
What this does
- Creates tickets (registrations) for each VIP attendee.
send_notification: true- Each attendee receives confirmation email with join link.fast_join: false- Attendees must verify email before joining (recommended for security).- Returns unique
event_join_linkfor each attendee.
Batch limits
You can pre-register up to 30 attendees per API call.
Step 6: Publish the event
Now it is time to make your CloudSync Pro Launch event live. Publishing activates all registration links and makes the event discoverable.
cURL
curl -X POST "https://api.zoom.us/v2/zoom_events/events/kNqLPC6hSFiZ9NpgjA549w/event_actions" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
-d '{
"operation": "publish"
}'
Python
import requests
event_id = "kNqLPC6hSFiZ9NpgjA549w"
url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}/event_actions"
headers = {
"Content-Type": "application/json",
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
publish_data = {
"operation": "publish"
}
response = requests.post(url, headers=headers, json=publish_data)
response.raise_for_status() # Check for HTTP errors
result = response.json()
print(f"Event published successfully")
print(f"Status: {result['status']}")
JavaScript (Node.js)
const axios = require("axios");
async function publishEvent(eventId) {
const url = `https://api.zoom.us/v2/zoom_events/events/${eventId}/event_actions`;
const headers = {
"Content-Type": "application/json",
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
const publishData = {
operation: "publish",
};
try {
const response = await axios.post(url, publishData, { headers });
const result = response.data;
console.log("Event published successfully");
console.log(`Status: ${result.status}`);
} catch (error) {
console.error(
"Failed to publish event:",
error.response?.data || error.message,
);
throw error;
}
}
publishEvent("kNqLPC6hSFiZ9NpgjA549w");
Expected Response
{
"status": "PUBLISHED",
"event_id": "kNqLPC6hSFiZ9NpgjA549w"
}
Results when you publish:
- Event status changes from
drafttopublished. - All registration links become active.
- Event appears in your hub (if hub is public).
- Confirmation emails are sent to pre-registered attendees.
- The event is now accessible to registrants.
Important: After publishing, certain fields become immutable (e.g., meeting_type, event_type).
Step 7: Verify your event
Confirm everything is set up correctly by retrieving the event details.
cURL
curl -X GET "https://api.zoom.us/v2/zoom_events/events/kNqLPC6hSFiZ9NpgjA549w" \
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
Python
import requests
event_id = "kNqLPC6hSFiZ9NpgjA549w"
url = f"https://api.zoom.us/v2/zoom_events/events/{event_id}"
headers = {
"Authorization": "Bearer YOUR_ACCESS_TOKEN"
}
response = requests.get(url, headers=headers)
response.raise_for_status() # Check for HTTP errors
event = response.json()
print("=" * 60)
print("CloudSync Pro Launch Event Summary")
print("=" * 60)
print(f"Event Name: {event['name']}")
print(f"Status: {event['status']}")
print(f"Event Type: {event['event_type']}")
print(f"Meeting Type: {event['meeting_type']}")
print(f"Start Time: {event['calendar'][0]['start_time']}")
print(f"Registration URL: {event['event_url']}")
print(f"Tagline: {event.get('tagline', 'N/A')}")
print("=" * 60)
JavaScript (Node.js)
const axios = require("axios");
async function verifyEvent(eventId) {
const url = `https://api.zoom.us/v2/zoom_events/events/${eventId}`;
const headers = {
Authorization: "Bearer YOUR_ACCESS_TOKEN",
};
try {
const response = await axios.get(url, { headers });
const event = response.data;
console.log("=".repeat(60));
console.log("CloudSync Pro Launch Event Summary");
console.log("=".repeat(60));
console.log(`Event Name: ${event.name}`);
console.log(`Status: ${event.status}`);
console.log(`Event Type: ${event.event_type}`);
console.log(`Meeting Type: ${event.meeting_type}`);
console.log(`Start Time: ${event.calendar[0].start_time}`);
console.log(`Registration URL: ${event.event_url}`);
console.log(`Tagline: ${event.tagline || "N/A"}`);
console.log("=".repeat(60));
} catch (error) {
console.error(
"Failed to verify event:",
error.response?.data || error.message,
);
throw error;
}
}
verifyEvent("kNqLPC6hSFiZ9NpgjA549w");
Expected Output
============================================================
CloudSync Pro Launch Event Summary
============================================================
Event Name: CloudSync Pro Launch
Status: PUBLISHED
Event Type: SIMPLE_EVENT
Meeting Type: WEBINAR
Start Time: 2025-12-15T19:00:00Z
Registration URL: https://zoom.us/events/abc123xyz
Tagline: The Future of Cloud Storage Starts Here
============================================================
Verification checklist
- Status is
published event_urlis accessible (share this link for registration)- Start/end times are correct
- Event details match your specifications
What you built
Congratulations! You have successfully created a complete single-session virtual event. Here is what you accomplished:
Event configuration
- Name: CloudSync Pro Launch
- Type: Single-session webinar (SIMPLE_EVENT)
- Capacity: Up to 100,000 attendees
- Date: December 15, 2025, 2:00 PM - 3:00 PM EST
- Status: Published and live
Registration setup
- Public registration link (no login required)
- Default "General Admission" ticket type
- Pre-registered 3 VIP attendees with confirmation emails
- Active registration URL ready to share
Next steps
Now that your event is live, you can:
-
Share the registration link
- Use
event_urlfrom the event response - Embed on your website or share via email/social media
- Use
-
Add branding (optional)
- Upload event logo and banner images
- Customize colors and themes via the Zoom web portal
-
Configure session settings
- Enable Q&A, polls, chat, reactions
- Set up breakout rooms for networking
- Configure recording settings
-
Add speakers/panelists
- Use
POST /zoom_events/events/{eventId}/speakersendpoint - Speakers appear on event page and in lobby
- Use
-
Monitor registrations
- Use
GET /zoom_events/events/{eventId}/registrantsto view attendees - Export registration data for analysis
- Use
-
Send reminder emails
- Zoom automatically sends reminders 1 day and 1 hour before
- Customize email templates via the web portal
Configuration options
Meeting vs. Webinar Mode
| Feature | MEETING | WEBINAR |
|---|---|---|
| Max Capacity | 1,000 attendees | 100,000 attendees |
| Video Sharing | All participants | Host/panelists only |
| Screen Sharing | All participants | Host/panelists only |
| Best For | Workshops, roundtables | Presentations, broadcasts |
When to use meeting: Interactive sessions where attendees need video/audio. When to use webinar: Large presentations where only hosts present.
Access levels
PRIVATE_UNRESTRICTED- Anyone can register via link (no approval needed)PRIVATE_RESTRICTED- Host must approve each registration
Attendance types
VIRTUAL- Online-only event (default)IN-PERSON- Physical venue onlyHYBRID- Both virtual and in-person attendees
For hybrid events, add physical_location field and enable check-in features.
Troubleshooting
Common errors
Error 26501: Event not published
Problem: Trying to create tickets before publishing event. Solution: Publish event first using Step 6, then create tickets.
Error 261202: Ticket type not found
Problem: Invalid ticket_type_id in request.
Solution: Retrieve valid ticket type ID using Step 3.
Error 260200: Event access denied
Problem: Insufficient permissions or wrong hub. Solution: Verify API scopes and ensure you have host access to the hub.
Error 26202: Event schedule cannot be more than 6 days
Problem: Single-session events have a 6-day maximum duration. Solution: Reduce session length or use CONFERENCE type for multi-session events.
Error 261203: Duplicate access link name
Problem: An access link with this name already exists. Solution: Use a unique name for each registration link.
API Reference quick links
- Create event
- Create registration link
- Pre-register attendees
- Publish, duplicate or cancel
- List event hubs
- List ticket types
Complete example code
Python full workflow
import requests
from datetime import datetime, timezone
# Configuration
BASE_URL = "https://api.zoom.us/v2/zoom_events"
ACCESS_TOKEN = "YOUR_ACCESS_TOKEN"
HEADERS = {
"Content-Type": "application/json",
"Authorization": f"Bearer {ACCESS_TOKEN}"
}
def create_product_launch_event():
# Step 1: Get Hub ID
hubs_response = requests.get(
f"{BASE_URL}/hubs",
headers={"Authorization": f"Bearer {ACCESS_TOKEN}"},
params={"role_type": "host"}
)
hubs_response.raise_for_status() # Check for HTTP errors
hub_id = hubs_response.json()["hubs"][0]["hub_id"]
print(f" Hub ID: {hub_id}")
# Step 2: Create Event
event_data = {
"hub_id": hub_id,
"name": "CloudSync Pro Launch",
"": "Join us for the exclusive launch of CloudSync Pro...
"timezone": "America/New_York",
"event_type": "SIMPLE_EVENT",
"access_level": "PRIVATE_UNRESTRICTED",
"meeting_type": "WEBINAR",
"attendance_type": "VIRTUAL",
"tagline": "The Future of Cloud Storage Starts Here",
"contact_name": "Sarah Chen",
"calendar": [
{
"start_time": "2025-12-15T19:00:00Z",
"end_time": "2025-12-15T20:00:00Z"
}
]
}
event_response = requests.post(f"{BASE_URL}/events", headers=HEADERS, json=event_data)
event_response.raise_for_status() # Check for HTTP errors
event_id = event_response.json()["event_id"]
print(f" Event created: {event_id}")
# Step 3: Get Ticket Type
ticket_types_response = requests.get(
f"{BASE_URL}/events/{event_id}/ticket_types",
headers={"Authorization": f"Bearer {ACCESS_TOKEN}"}
)
ticket_types_response.raise_for_status() # Check for HTTP errors
ticket_type_id = ticket_types_response.json()["ticket_types"][0]["ticket_type_id"]
print(f" Ticket Type ID: {ticket_type_id}")
# Step 4: Create Registration Link
link_data = {
"name": "Public Registration",
"type": "registration",
"is_default": True,
"authentication_method": "bypass_auth",
"ticket_type_id": ticket_type_id,
"security_at_join": {
"email_authentication": False,
"security_code_verification": False
}
}
link_response = requests.post(
f"{BASE_URL}/events/{event_id}/access_links",
headers=HEADERS,
json=link_data
)
link_response.raise_for_status() # Check for HTTP errors
print(f" Registration link created")
# Step 5: Pre-register VIPs
tickets_data = {
"tickets": [
{
"email": "alex.rivera@techcorp.com",
"first_name": "Alex",
"last_name": "Rivera",
"ticket_type_id": ticket_type_id,
"send_notification": True,
"fast_join": False
},
{
"email": "jordan.patel@innovate.io",
"first_name": "Jordan",
"last_name": "Patel",
"ticket_type_id": ticket_type_id,
"send_notification": True,
"fast_join": False
}
]
}
tickets_response = requests.post(
f"{BASE_URL}/events/{event_id}/tickets",
headers=HEADERS,
json=tickets_data
)
tickets_response.raise_for_status() # Check for HTTP errors
print(f" Pre-registered {len(tickets_response.json()['tickets'])} VIPs")
# Step 6: Publish Event
publish_response = requests.post(
f"{BASE_URL}/events/{event_id}/event_actions",
headers=HEADERS,
json={"operation": "publish"}
)
publish_response.raise_for_status() # Check for HTTP errors
print(f" Event published")
# Step 7: Get Event URL
event_details_response = requests.get(
f"{BASE_URL}/events/{event_id}",
headers={"Authorization": f"Bearer {ACCESS_TOKEN}"}
)
event_details_response.raise_for_status() # Check for HTTP errors
event_details = event_details_response.json()
print("\n" + "="*60)
print("EVENT CREATED SUCCESSFULLY")
print("="*60)
print(f"Event Name: {event_details['name']}")
print(f"Registration URL: {event_details['event_url']}")
print(f"Start Time: {event_details['calendar'][0]['start_time']}")
print("="*60)
if __name__ == "__main__":
create_product_launch_event()
Tutorial complete
You now know how to create, configure, and publish a single-session virtual event using the Zoom Webinars Plus & Events API.
Questions or issues? Check the Troubleshooting section or visit the Zoom Developer Forum.