Zoom webhook is not validating or sending request

I’m trying to set up a separate server-to-server app for production, distinct from my staging environment. Everything is working perfectly in staging, but in production, the webhook URL validation keeps failing—even though I’m following the exact same process.

When I attempt to validate the production URL:

https ://api-dev.mastersunion.in/api/v1/zoom/zoomReport
I receive the error: “URL validation failed. Try again later.”

To troubleshoot, I tried using ngrok to inspect incoming requests on localhost. Surprisingly, any ngrok URL I use gets validated instantly, without even hitting my backend. That suggests the validation process isn’t actually triggering on my server during this step.

So my questions are:

How exactly is the URL validation being done on your end?

Is there some kind of allowlist/denylist for domains during validation?

If so, how can I ensure my production domain (api-dev.mastersunion.in) is whitelisted?

If not, what else could be causing the validation to silently fail for this specific URL?

Any help or clarification would be much appreciated!

 for (const hostDetail of hostDetails) {
    const hashForVerify = crypto.createHmac('sha256', hostDetail.webhookSecretToken)
      .update(message)
      .digest('hex');

    const signature = `v0=${hashForVerify}`;
    console.log(req.body.event, "req.body.event");

    if (req.headers['x-zm-signature'] === signature) {
      if (req.body.event === 'endpoint.url_validation') {

        
        const hashForValidate = crypto.createHmac('sha256', hostDetail.webhookSecretToken)
          .update(req.body.payload.plainToken)
          .digest('hex');

        response = {
          message: {
            plainToken: req.body.payload.plainToken,
            encryptedToken: hashForValidate
          },
          status: 200
        };

        console.log(response.message, hostDetail,"hosttttttt");

        res.status(response.status);
        res.json(response.message);
      } else if (req.body.event === 'meeting.ended') {
        const id = req.body.payload.object.id; 

        await zoomService.zoomAttendance(id, hostDetail); 

        response = { message: 'Meeting end event processed successfully.', status: 200 };

        console.log(response.message);

        res.status(response.status);
        res.json(response);
      } else {
        response = { message: 'Authorized request to Zoom Webhook sample.', status: 200 };

        console.log(response.message);

        res.status(response.status);
        res.json(response);
      }
    } else {
      response = { message: 'Unauthorized request to Zoom Webhook sample.', status: 401 };

      console.log(response.message);

      res.status(response.status);
      res.json(response);
    }
  }

Hi @Zoom100
Thanks for reaching out to us and welcome to the Zoom Developer Forum.
We de not have a denylist in place for domains, but the issue you are seeing with ngrok is expected, as it is a known and approve domain we don’t enforce validation for now. But we do not white list specific domains.
Your logic looks good, so my question is, are you getting any errors when triggering validation, or what do you see in your console?

hi @Zoom100
i thought that you must have your app approved to run production. So, can I confirm you applied for production from zoom? I dont think people do that for server auth.
they are running an app for their own domain and it is not shared.
If you are running server auth then there is no production?
Just an out of box suggestion?
all the best

John
all the best

John

Hi @Elisa,

I’m encountering an issue where nothing appears in my ngrok console or the VSCode terminal. As a result, I don’t see any errors, and it seems the API isn’t being triggered.

Hi @Zoom100
As I mentioned, we do not enforce validation on ngrok since its is a known domain, could you please try and save your subscription and start and end a couple of meetings, to check if the meeting.ended event gets triggered pleasE?

Hi Elisa,

I’m currently facing an issue similar to the one we discussed earlier, but it’s not related to using Ngrok.

I tested the webhook functionality locally using Ngrok, and everything worked as expected — the webhook successfully received meeting action events and my implementation was fully functional.

However, after moving the project to a production environment and using a live domain, the webhook URL is failing validation during the Zoom integration process. The same logic and structure are in place, but the live URL doesn’t seem to pass Zoom’s validation checks.

Do you have any insight into what might be causing this issue? Are there specific requirements or configurations (e.g., SSL, headers, response structure) that need to be in place for webhook validation to succeed on a live domain?

Any guidance would be greatly appreciated.
For your kind refrence this is the main url i want to use as webhook

Hi @Vritti
Thanks for reaching out and welcome to the Zoom Developer forum!
Happy to help here!

Here are a couple of links to our docs on some of the Requirements needed to validate your URL

Here is the link to how to validate your webhook endpoint, note that you have to manually trigger the validation