Best Way to Extract Webinar Registrants via Zoom API?

We’re currently pulling data from the /v2/webinars/{webinarId}/registrants endpoint, but we’ve run into an issue: some registrants that our operations team sees as valid registrations aren’t showing up in the API response.

When asked how those webinars were created, they said: *These were created as a zoom event which now falls under “events and sessions”, but they are in webinar form meaning the audience cannot be seen. *

I joined the Zoom drop-in session, and we were advised to use this endpoint instead: /v2/zoom_events/events/{eventId}/registrants

We attempted to call that Events API endpoint using our server-to-server OAuth app (which has all the Events scopes enabled), but the request returns: {‘code’: 124, ‘message’: ‘Invalid Access token’}

API Call

url = f’https://zoom.us/oauth/token?grant_type=account_credentials&account_id={account_id}

def get_zoom_token():
response = requests.post(url, auth=(self.user, self.password))

return response.json().get('access_token')

We reviewed the Zoom Events and couldn’t find any note indicating that server-to-server OAuth is unsupported for this endpoint.

We’re extracting registration data from the API to our data warehouse, so interactive OAuth flows are not a viable option for our use case.

Why do some users appear in the Zoom UI as registrants but not in the /webinars/{webinarId}/registrants API?

How does Zoom define a “registration” for the webinar API? (in their report those users show up as
self-registration by email)

Does the /zoom_events/events/{eventId}/registrants endpoint support Server-to-Server OAuth?

If not, what is the recommended approach for backend automation that pulls registrant data from Zoom Events?

Hey @BrunoSerafim
thanks for reaching out to us and welcome to the Zoom Developer Forum!
This is an interesting issue, when you generate your access token, are you able to see the scope to access the endpoint you are aiming in your response?

Thanks for the follow-up!

Here’s the token response we’re getting: {‘access_token’: token,
‘token_type’: ‘bearer’,
‘expires_in’: 3600,
‘scope’: ‘webinar:read:list_webinars:admin webinar:read:webinar:admin webinar:read:list_registrants:admin webinar:read:registrant:admin webinar:read:list_panelists:admin webinar:read:list_past_instances:admin webinar:read:list_absentees:admin webinar:read:list_past_participants:admin webinar:read:list_registrants:master zoom_events:read:event:admin zoom_events:read:list_events:admin zoom_events:read:list_registrants:admin zoom_events:read:list_session_attendees:admin report:read:meeting:admin report:read:webinar:admin report:read:list_webinar_participants:admin report:read:list_webinar_polls:admin report:read:webinar_qna:admin dashboard:read:post_webinar_feedback:admin dashboard:read:webinar:admin dashboard:read:webinar_participant_qos:admin dashboard:read:list_webinar_participants:admin dashboard:read:webinar_sharing:admin dashboard:read:meeting_survey:admin dashboard:read:list_webinar_participants_qos:admin dashboard:read:list_webinars:admin’, ‘api_url’: ‘https://api.zoom.us’}

The highlited ones: zoom_events:read:event:admin
zoom_events:read:list_events:admin
zoom_events:read:list_registrants:admin
zoom_events:read:list_session_attendees:admin

Following the documentation, we added the required scopes via the Zoom App Marketplace and generated the token afterward using our Server-to-Server OAuth app credentials.

Thanks for sharing this with me @BrunoSerafim
This looks right, I am reviewing the docs and I can see the right scopes are added to your app so you should not be getting this error.
Jus to confirm, you have a Zoom sessions/events license in your account correct?
Lastly could you please share with me the tracking ID found in the request headers of this API call? /v2/zoom_events/events/{eventId}/registrants

Hi @Bruno, welcome to the community!

The best approach for reliably extracting Zoom webinar registrants — especially with Zoom Events involved — is to bind to Zoom’s Webhook system and listen for the webinar.registration_created event. This event fires in real-time whenever a registrant successfully signs up and includes all relevant payload data (name, email, etc.) that you can immediately sync to your database or data warehouse.

This has several advantages over polling API endpoints:

  • Real-time updates
  • No missing registrants due to API inconsistency or differences between webinars vs. Zoom Events
  • Fully backend-compatible – Webhooks work seamlessly with Server-to-Server OAuth setups

To set this up:

  1. Go to your Zoom App in the Marketplace.
  2. Enable Event Subscriptions.
  3. Subscribe to webinar.registration_created and optionally other related events like webinar.registration_approved.
  4. Set your endpoint to receive and process the payload.

As for the /zoom_events/events/{eventId}/registrants endpoint: it’s true that Zoom Events APIs behave differently and may have limited support with Server-to-Server OAuth. The webhooks route avoids these restrictions and gives you a unified way to track both regular webinars and Zoom Events when registration is triggered.

Let me know if you need help setting up the webhook listener or handling the payload!

Jus to confirm, you have a Zoom sessions/events license in your account correct?
I believe so, this is my plan details:

Lastly could you please share with me the tracking ID found in the request headers of this API call? calling the /v2/zoom_events/events to retrieve the events id’s to call the registrants endpoint:
WEB_6fd2890d00312318a2191ef81a996ea1

Hey @BrunoSerafim
Sorry for the late reply here, I did not get a notification when you replied.
Yes, it looks like the correct license.

You shared this
“calling the /v2/zoom_events/events to retrieve the events id’s to call the registrants endpoint:
WEB_6fd2890d00312318a2191ef81a996ea1”

But can you share a tracking id when calling this endpoint please: /v2/zoom_events/events/{eventId}/registrants

I’ve added a ‘X-Tracking-ID’: ‘zoom-forum-132518’ in my headers while calling the v2/zoom_events/events/{eventId}/registrants

This is the response headers: {‘Date’: ‘Tue, 27 May 2025 14:28:52 GMT’, ‘Content-Type’: ‘application/json; charset=utf-8’, ‘Transfer-Encoding’: ‘chunked’, ‘Connection’: ‘keep-alive’, ‘x-zm-trackingid’: ‘WEB_93ee0910c7c8adb9bf8e6ea215413780’, ‘zm-nws-cluster’: ‘aw1’, ‘strict-transport-security’: ‘max-age=31536000; includeSubDomains’, ‘cf-cache-status’: ‘DYNAMIC’, ‘Set-Cookie’: ‘__cf_bm=m[…]Y; path=/; expires=Tue, 27-May-25 14:58:52 GMT; domain=.zoom.us; HttpOnly; Secure; SameSite=None’, ‘Report-To’: ‘{“endpoints”:[{“url”:“https:\/\/a.nel.cloudflare.com\/report\/v4?s=[…]”}],“group”:“cf-nel”,“max_age”:604800}’, ‘NEL’: ‘{“success_fraction”:0.01,“report_to”:“cf-nel”,“max_age”:604800}’, ‘Server’: ‘cloudflare’, ‘CF-RAY’: ‘94663380885b9510-JOI’, ‘alt-svc’: ‘h3=“:443”; ma=86400’}

Hope this helps!

Thanks @BrunoSerafim
and just to confirm, you are getting : {‘code’: 124, ‘message’: ‘Invalid Access token’} when calling that endpoint right?

Yep, 401 and the text: {“code”:124, “message”:“Invalid Access token”}

I’m using a Server-to-Server OAuth app with the account_credentials grant type.

1 Like

Thanks @BrunoSerafim
I created an internal ticket so our team can take a closer look at this (ZSEE-168659)

1 Like

Hey @BrunoSerafim could you please generate a new access token and make a request to the same endpoint, passing but without the query param page_size please and share the tracking ID again
Just like this: /v2/zoom_events/events/{eventId}/registrants

Also, could you confirm you are using the right event ID, you can get it from this endpoint: Events APIs