# Webinar - Wrong Rate Limit applied

**URL:** <https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482>\
**Category:** Webinars\
**Tags:** api\
**Created:** [December 16, 2024, 8:52am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482 "2024-12-16T08:52:51Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [December 16, 2024, 8:52am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/1 "2024-12-16T08:52:51Z")

</div>

### Format Your New Topic as Follows:

**API Endpoint(s) and/or Zoom API Event(s)**  
PUT /webinars/{webinarId}/registrants/status

_Link the API endpoint(s) and/orZoom API Event(s) you’re working with to help give context._  
 → /api/rest/reference/zoom-api/methods/#operation/webinarRegistrantStatus

**Description**  
We organized a webinar for 1000 attendees.  
We registered and approved attendees one by one by APIs call in a row.

- POST /webinars/{webinarId}/registrants
- PUT /webinars/{webinarId}/registrants/status

Only 10 attendees were able to join the webinar. We got 429 status code on all our queries after.

**Error?**  
_The full error message or issue you are running into, where applicable._

“You have exceeded the daily rate limit of (10) for webinar Update registrant's status API requests for the registrant”

It seems rate limit aren’t applied as describe. We made Unit Test to test it :

- We create 30 attendees one by one running :

- POST /webinars/{webinarId}/registrants  
then
- PUT /webinars/{webinarId}/registrants/status

- Always failed to the eleventh

Registrants (id and email) are always different, we are using the registrantId given from the POST response to the PUT query.

Means the limit describe isn’t working as expected : “Registrant status requests  
10 requests per day (UTC) for **the same registrant in the** same meeting/webinar”

**How To Reproduce**  
_Steps to reproduce the behavior:_  
Here are our 2 tests files. (well… I had to copy, I can’t join file to the topic)  
There is a fixture file containing 30 users with different emails, then this PHP File :

```auto
class ZoomApiTest extends KernelTestCase
{
    use IntegrationTestTrait;

    protected function setUp(): void
    {
        $kernel = self::bootKernel(['env' => 'test']);
        $this->app = new Application($kernel);
    }

    /**
     * Testing the Zoom rate-limit for registrant status request
     * https://developers.zoom.us/docs/api/rate-limits/
     */
    public function testAddingAttendeesToWebinar(): void
    {
        // Load the fixtures
        $this->loadFixture( __DIR__. '/../../../features/bootstrap/fixtures/webinar/webinar_playwright_load_testing.yml');

        /** @var WebinarAttendeeRepository $attendeesRepository */
        $attendeesRepository = static::getContainer()->get(WebinarAttendeeRepository::class);

        /** @var WebinarRepository $webinarRepository */
        $webinarRepository = static::getContainer()->get(WebinarRepository::class);

        /** @var WebinarAttendee[] | null $attendees */
        $attendees = $attendeesRepository->findBy(['status' => WebinarAttendee::STATUS_ATTENDEE]);

        $webinar = $webinarRepository->find('webinar2');
        $this->assertInstanceOf(Webinar::class, $webinar);

        // 30 attendees
        $this->assertCount(30, $attendees);

        try {
            $webinarResponse = $this->createWebinar($webinar);
            $this->assertInstanceOf(CreateWebinarResponse::class, $webinarResponse);
            $this->assertNotEmpty($webinarResponse->getZoomWebinarId());
        } catch (ZoomException $e) {
            $this->fail($e->getMessage());
        }

        foreach ($attendees as $key => $attendee) {
            try {
                $response = $this->joinWebinarAsAttendee($attendee, $webinarResponse->getZoomWebinarId());
                $this->assertInstanceOf(JoinWebinarResponse::class, $response);
            } catch (ZoomException $e) {
                // Rate limit after 10 users
                // 10 requests per day (UTC) for the same registrant in the same meeting/webinar
                $this->assertStringContainsString('You have exceeded the daily rate limit of (10) for webinar Update registrant\'s status API requests for the registrant', $e->getMessage());
                $this->assertGreaterThanOrEqual(10, $key);
            }
        }
    }

    /**
     * @throws ZoomException
     * @throws DateInvalidTimeZoneException
     */
    public function createWebinar(Webinar $webinar): CreateWebinarResponse
    {
        $dateDiff = $webinar->getStartDate()->diff($webinar->getEndDate());
        $duration = $dateDiff->i + ($dateDiff->h * 60);

        $startDate = clone $webinar->getStartDate();
        $startDate->setTimezone(new DateTimeZone($webinar->getTimezone()));

        $response = $this->callApi(
            'POST',
            '/v2/users/me/webinars',
            [
                'agenda' => $webinar->getSummary(),
                "topic" => $webinar->getTitle(),
                "start_time" => $startDate->format('Y-m-d\TH:i:s'),
                "duration" => $duration,
                "timezone" => $webinar->getTimezone(),
                "type" => 5,
                // Manually approve
                "settings" => [
                    "approval_type" => 1,
                    "allow_multiple_devices" => false,
                    "auto_recording" => "cloud",
                    "panelists_invitation_email_notification" => false,
                    "registrants_email_notification" => false,
                    "practice_session" => true,
                    "panelists_video" => true,
                    "host_video" => true,
                    "question_and_answer" => [
                        "enabled" => true,
                        "allow_submit_questions" => true,
                        "allow_anonymous_questions" => false,
                        "answer_questions" => "all",
                        "attendees_can_comment" => true,
                        "attendees_can_upvote" => true,
                    ]
                ]
            ]
        );

        try {
            $data = $response->toArray();
            return new CreateWebinarResponse($data['id'], $data['start_url']);
        } catch (ExceptionInterface $e) {
            throw new ZoomException('An error occurred while creating webinar', 0, $e);
        }
    }

    public function joinWebinarAsAttendee(WebinarAttendee $attendee, string $webinarZoomId): JoinWebinarResponse
    {
        $response = $this->callApi(
            'POST',
            '/v2/webinars/' . $webinarZoomId . '/registrants',
            [
                'email' => $attendee->getUser()->getEmail(),
                'first_name' => $attendee->getUser()->getFirstName(),
                'last_name' => $attendee->getUser()->getLastName(),
                'address' => $attendee->getUser()->getAddress(),
                'language' => 'fr-FR'
            ]
        );
        $addRegistrantResponseData = $response->toArray();

        if ($response->getStatusCode() !== 201) {
            $message = $response->toArray(false)['message'] ?? 'An error occurred while adding registrant';
            throw new ZoomException($message);
        }

        $response = $this->callApi(
            'PUT',
            '/v2/webinars/' . $webinarZoomId . '/registrants/status',
            [
                'action' => 'approve',
                'registrants' => [
                    [
                        'id' => $addRegistrantResponseData['id'],
                        'email' => $attendee->getUser()->getEmail(),
                    ]
                ]
            ]
        );

        if ($response->getStatusCode() !== 204) {
            $message = $response->toArray(false)['message'] ?? 'An error occurred while adding registrant';
            throw new ZoomException($message);
        }
        return new JoinWebinarResponse($addRegistrantResponseData['join_url']);
    }

    private function callApi(string $httpVerb, string $uri, array $jsonPayload = null): ResponseInterface
    {
        $httpClient = HttpClient::createForBaseUri('https://zoom.us');

        $options = [
            'headers' => [
                "Authorization" => "Bearer {$this->getAccessToken()}"
            ]
        ];

        if ($jsonPayload) {
            $options['json'] = $jsonPayload;
        }

        try {
            return $httpClient->request($httpVerb, $uri, $options);
        } catch (ClientException|TransportExceptionInterface $e) {
            throw new ZoomException('An error occurred while calling Zoom API', 0, $e);
        }
    }

    private function getAccessToken(): string
    {
        $httpClient = HttpClient::createForBaseUri('https://zoom.us');
        $accountId = self::getContainer()->getParameter('zoomAccountId');
        $clientId = self::getContainer()->getParameter('zoomClientId');
        $clientSecret = self::getContainer()->getParameter('zoomClientSecret');

        // get access token from zoom
        $response = $httpClient->request('POST', '/oauth/token', [
            'query' => [
                'grant_type' => 'account_credentials',
                'account_id' => $accountId,
            ],
            'headers' => [
                'Authorization' => 'Basic ' . base64_encode("{$clientId}:{$clientSecret}")
            ]
        ]);

        return $response->toArray()['access_token'];
    }
}

```

Could you please, take a look, and explain.

Regards,

---

<div class="post-metadata">

**Author:** ![chunsiong.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/chunsiong.zoom/32/35488_2.png) [@chunsiong.zoom](https://devforum.zoom.us/u/chunsiong.zoom)\
**Post date:** [December 17, 2024, 7:43am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/2 "2024-12-17T07:43:13Z")

</div>

@ITNetwork ,

Since you mentioned it failed on the 11th attempt, it worth looking at the API which are limited to 10 per seconds or 10 per minute.

> **[Rate limits - Zoom Developers](https://developers.zoom.us/docs/api/rate-limits/#rate-limits-by-account-type)**
>
> The Zoom Developer Platform is an open platform that allows third-party developers to build applications and integrations upon Zoom’s video-first unified communications platform.

there is another specific restriction which you might be encountering. This will only happen if you are using the same exact registrant for the same exact webinar. There is a rate limit of 10 calls per day.

> **[Rate limits - Zoom Developers](https://developers.zoom.us/docs/api/rate-limits/#registrant-status-requests)**
>
> The Zoom Developer Platform is an open platform that allows third-party developers to build applications and integrations upon Zoom’s video-first unified communications platform.

---

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [December 17, 2024, 8:22am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/3 "2024-12-17T08:22:10Z")

</div>

@chunsiong.zoom

We already have a look those limits before implementing.

/webinars/{webinarId}/registrants/status ENDPOINT as Meduim Rate Limit Label : 20/sec.

Anyways, the JSON response clearly indicates we are hitting your second link :

### Registrant status requests

- 10 requests per day (UTC) for the **same** registrant in the same meeting/webinar

But it’s not working properly. We are requesting registrant status on a DIFFERENT registrant on each call. Not the “SAME” as you can see on the bug reproduction. The rate limit shouldn’t be hit.

Could you please check around this point.

Regards,

---

<div class="post-metadata">

**Author:** ![chunsiong.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/chunsiong.zoom/32/35488_2.png) [@chunsiong.zoom](https://devforum.zoom.us/u/chunsiong.zoom)\
**Post date:** [December 17, 2024, 8:29am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/4 "2024-12-17T08:29:25Z")

</div>

@ITNetwork when you get the 429 error, could you check the response header for a web tracking ID?

it should be something like zm-tracking-id

---

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [December 17, 2024, 8:54am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/5 "2024-12-17T08:54:53Z")

</div>

> [@chunsiong.zoom](#):
>
> when you get the 429 error, could you check the response header for a web tracking ID?
> 
> it should be something like zm-tracking-id

@chunsiong.zoom  
We just rerun the test to get one :

x-zm-trackingid: v=2.0;clid=aw1;rid=WEB\_4d5d38054f69b3577ce44203be60a72d

---

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [December 17, 2024, 9:43am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/6 "2024-12-17T09:43:24Z")

</div>

@chunsiong.zoom Not sure you get the tag, because I tagged you on edit. Sorry.

---

<div class="post-metadata">

**Author:** ![chunsiong.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/chunsiong.zoom/32/35488_2.png) [@chunsiong.zoom](https://devforum.zoom.us/u/chunsiong.zoom)\
**Post date:** [December 17, 2024, 12:02pm UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/7 "2024-12-17T12:02:57Z")

</div>

@ITNetwork I’ve managed to replicate this, and will be investigating.

Internal reference usage: ZSEE-151972

---

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [December 17, 2024, 12:15pm UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/8 "2024-12-17T12:15:37Z")

</div>

@chunsiong.zoom  
Great ! Thanks.  
Looking forward to your investigation,  
Regards,

---

<div class="post-metadata">

**Author:** ![chunsiong.zoom](https://sea2.discourse-cdn.com/flex016/user_avatar/devforum.zoom.us/chunsiong.zoom/32/35488_2.png) [@chunsiong.zoom](https://devforum.zoom.us/u/chunsiong.zoom)\
**Post date:** [December 23, 2024, 7:37am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/9 "2024-12-23T07:37:55Z")

</div>

@ITNetwork when approving the user using the registrants/status endpoint, you will need to put in the email and id. Do note that the id in this instance is the registrant id instead of the webinar id.

It should work once you input the correct registrant id.

---

<div class="post-metadata">

**Author:** ![ITNetwork](https://avatars.discourse-cdn.com/v4/letter/i/5fc32e/32.png) [@ITNetwork](https://devforum.zoom.us/u/ITNetwork)\
**Post date:** [January 6, 2025, 10:04am UTC](https://devforum.zoom.us/t/webinar-wrong-rate-limit-applied/122482/10 "2025-01-06T10:04:04Z")

</div>

@chunsiong.zoom

Indeed, we are sending webinarId instead of registrantId.  
Thanks for your assistant.

Yet, sending the webinarId, approve correctly the registrant (by the other fields I guess : email) because we got 10 registrants approved by passing wrong “id”. We are sending a wrong data, it works as expected, the API doesn’t throw any issue.  
There is no check on your part to confirm “registrantId” has been added with the “email” used on endpoint : post /webinars/{webinarId}/registrants (which return the registrantId)  
Is it normal ?

Regards,
