API Endpoint / Zoom API Event:endpoint.url_validation - Event Notification Endpoint URL validation on Zoom Marketplace Production app
Description: I have a General App in Production submission. My webhook endpoint correctly handles the endpoint.url_validation challenge but the Zoom Marketplace keeps showing “URL validation failed. Try again later.” every time I click Validate.
When Validate is clicked, Zoom sends a POST with endpoint.url_validation event. My server receives it, hashes the plainToken with HMAC-SHA256 using the correct secret token, and returns { plainToken, encryptedToken } with HTTP 200.
Railway HTTP logs confirm the request hits the server and returns 200. Deploy logs confirm the correct plainToken and hash are generated. The secret token in the server environment matches exactly what is shown in the Marketplace app. Despite all of this the validation fails every time.
Is there a known issue with webhook validation for Production General Apps currently in submission?
One thing to note is Zoom requires the exact endpoint.url_validation handshake response - your handler has to return top-level plainToken and encryptedToken fields, and encryptedToken has to be derived from your app’s current Secret Token. A 200 alone is not enough if the body shape, token source, or digest output differs from what Zoom expects.
The most useful check here is to capture the raw production validation response that Zoom actually receives and compare it byte-for-byte with Zoom’s sample shape. Verify that your final public HTTPS endpoint URL accepts the POST directly, returns JSON from the root object with no wrapper, redirect, auth challenge, or HTML, and that the Secret Token is the Production app value, not a stale env var from Development. If that raw capture is clean, this looks like a support case rather than an implementation gap, so send Zoom the app ID, validation timestamp, and full raw request and response pair.
If you would prefer not to manage this integration complexity on your end, you might want to try out Recall.ai’s Meeting Bot API. It’s a simple API that allows you to fetch recordings and transcripts from Zoom calls, both live and after the call has ended.
Thank you for the detailed response. I’ve verified all of the points you raised:
The endpoint returns top-level plainToken and encryptedToken with no wrapper
HTTP 200 is returned with JSON only, no redirects, no HTML, no auth challenge
The Secret Token in the server environment is the Production app value and matches exactly what is shown in the Marketplace
Here is the raw evidence from Railway logs when Zoom hit the endpoint:
Zoom webhook received: endpoint.url_validation
Full payload: { "plainToken": "8AtVhiSCQ4-LrgsRL3SyaQ" }
Validation plainToken: 8AtVhiSCQ4-LrgsRL3SyaQ
Validation hash: fcdcf3314ca1f34b652c781176f46fa2941e35cf8f81ec2e5a947587e45a4fb2
Validation secret: o99IBexqRFywrBIR0I3BMw
HTTP Status returned: 200 in ~130ms
Railway HTTP logs show every validation attempt returns 200. The implementation matches Zoom’s documented sample shape exactly.
Given that the raw capture is clean as you described, this does appear to be a support case rather than an implementation gap. Unfortunately Zoom support informed me I need a paid account to submit a technical case. Is there any way to escalate this from your end, or advise on another path forward?
To address your point about body shape and digest output - the response body returned is exactly:
No wrapper, no extra fields. The HMAC-SHA256 digest is generated using Node.js crypto.createHmac('sha256', secretToken).update(plainToken).digest('hex') matching Zoom’s documented method exactly. Content-Type returned is application/json.
// Define a function to handle webhook requests
function handleWebhookRequest(req, res, secretToken, path) {
if (req.method === ‘POST’) {
// Check if the event type is “endpoint.url_validation”
if (req.body.event === ‘endpoint.url_validation’) {
const hashForValidate = crypto.createHmac(‘sha256’, secretToken)
.update(req.body.payload.plainToken)
.digest(‘hex’);
Thank you for sharing the sample. I can confirm our implementation matches this exactly:
We check req.body.event === 'endpoint.url_validation'
We hash req.body.payload.plainToken using crypto.createHmac('sha256', secretToken).update(plainToken).digest('hex')
We return res.status(200).json({ plainToken, encryptedToken })
The code is functionally identical to your sample. Railway logs confirm the correct values are being processed and 200 is returned. This does not appear to be an implementation issue. Could you escalate this to the Zoom developer team for investigation on the platform side?
I confirmed our implementation matches your sample exactly and posted the evidence above. I wanted to flag that you previously helped enable RTMS on my account manually, and that access expires May 15 which is in 3 days. The webhook validation failure is blocking my Production app submission which would make RTMS permanent. Is there any way you can help escalate this or extend the RTMS access while this gets resolved? Really appreciate your help.