URL validation failed for Server-to-Server OAuth webhook endpoint (CRC response is correct)

**Description**

The “Validate” button in the Zoom Marketplace always returns “URL validation failed. Try again later.” for our webhook endpoint. However, the endpoint correctly handles the CRC challenge-response check and returns the proper HMAC-SHA256 encrypted token.

**App Type:** Server-to-Server OAuth (Account-level)

**App Name:** Nerve Center Integration

**Webhook URL:** `Nerve Center | SYNERGY HomeCare

**Events subscribed:** phone.sms_received, phone.sms_sent (Zoom Phone category)

**What we’ve verified:**

1. The endpoint accepts POST requests and returns HTTP 200 with correct JSON:

```json

{

“plainToken”: “qgg8vlvZRS6UYooatFL8Aw”,

“encryptedToken”: “5a1cb91d30f704f4ca4801ba22e0249269546981ea7035dad19c2f4ed1e32e4a”

}

```

2. The HMAC-SHA256 hash is computed correctly using our Secret Token against the plainToken value. We’ve verified this independently with Python, Node.js, and curl.

3. SSL: Valid Amazon ACM certificate (TLS 1.3), cert issued 03/20/2026, expires 10/03/2026.

4. Response time: ~83ms (well within any timeout window).

5. The endpoint is publicly accessible with no firewall restrictions, no WAF blocking, and no Cloudflare or CDN in front of it (direct AWS ALB).

6. We’ve tried validating multiple times over several hours with the same result.

**Infrastructure:** AWS ECS Fargate behind an Application Load Balancer, Node.js HTTP server. The endpoint specifically handles the `endpoint.url_validation` event and responds with `{ plainToken, encryptedToken }` as documented.

**Questions:**

- Is there a known issue with the Validate button for Server-to-Server OAuth apps subscribing to Zoom Phone SMS events?

- Can a Zoom engineer manually trigger the validation or inspect why it’s failing from the Zoom side?

- Will the webhook still receive events even though the Validate button fails? The subscription appears to be saved.

Thank you for any help.

@Rob5 can you check against this code? This is something which I use in my demo environment

`// 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’);

res.status(200).json({
  "plainToken": req.body.payload.plainToken,
  "encryptedToken": hashForValidate
});

} else {

res.status(200).send();

}
}else if (req.method === ‘GET’) {

} else {
// Handle unsupported HTTP methods
res.status(405).send(“Method Not Allowed”);
}

}`