Guides · Free check · $9 fix pack

Guides

Polar webhook signature failing? The 8 Sep 2026 secret rule, and other 403 causes

If Polar webhooks fail signature checks or show 403s in the delivery log, start with when your webhook secret was created. Polar now uses two signing schemes, and generic libraries only work with one of them by default.

The two schemes

Polar's docs: "Secrets generated on or after 8 September 2026, 00:00 UTC are Standard Webhooks. Older secrets are Polar HMAC." For an older secret, the HMAC key "is the UTF-8 bytes of the full whsec_… string. Base64-encode that string before you hand it to a Standard Webhooks library." For a newer secret, "pass the whsec_… secret to the library as-is." And: "Polar SDKs 1.0.0-alpha.19 and later try both keys" (Polar docs: Handle & monitor webhook deliveries).

Either way, Polar sends the Standard Webhooks headers webhook-id, webhook-timestamp and webhook-signature. The signed content is msg_id.timestamp.payload, and signatures are serialized as v1, plus base64, space-separated when there is more than one (Standard Webhooks spec).

Why so many people hit this: Polar issue #13519

Issue #13519, opened Aug 3, 2026, reported that Polar's signatures didn't follow the Standard Webhooks key derivation. As a result, "any generic Standard Webhooks-compliant library (svix, standardwebhooks, or a hand-rolled implementation per our own docs) will compute a different key and fail verification on 100% of deliveries." Polar's own SDKs worked, because they used the literal secret bytes. A maintainer closed it on Oct 13, 2026 with "This is fixed now" (polarsource/polar issue #13519).

What that means for you: if you verified with svix or standardwebhooks and every delivery failed before Oct 13, that was very likely this bug. Today, follow the two-scheme rule above, or simply use Polar's SDK (1.0.0-alpha.19 or later), which tries both keys. The issue doesn't spell out what changed in the fix, so confirm yours with a redelivery from Polar's delivery overview.

The fix: Polar's SDK, raw body, 403 on failure

import express from "express";
import { webhooks } from "@polar-sh/sdk/2026-10";   // SDK 1.0.0-alpha.19+ tries both signing keys

const app = express();
app.post("/webhook", express.raw({ type: "application/json" }), async (req, res, next) => {
  try {
    const event = await webhooks.validateEvent(
      req.body,
      {
        "webhook-id": req.header("webhook-id") ?? "",
        "webhook-timestamp": req.header("webhook-timestamp") ?? "",
        "webhook-signature": req.header("webhook-signature") ?? "",
      },
      process.env.POLAR_WEBHOOK_SECRET ?? "",
    );
    // queue the event, answer fast
    res.status(202).send("");
  } catch (error) {
    if (error instanceof webhooks.PolarWebhookVerificationError) return res.status(403).send("");
    if (error instanceof webhooks.PolarWebhookUnknownTypeError) return res.status(202).send(""); // newer event type: ack, don't retry
    next(error);
  }
});

From Polar's docs (source). The import path follows the SDK version you have installed.

Other reasons for a 403

Redirects, 404s and timeouts

"Redirect responses (301, 302, 307, etc.) are treated as failures. Polar does not follow redirects", and www vs non-www redirects on hosts like Vercel are a common cause. For a 404, Polar suggests trying the trailing-slash form of the URL. Polar times out after 10 seconds and recommends responding within 2 (source).

Don't let the endpoint get disabled

Polar retries a failed delivery up to 10 times, and "webhook endpoints are automatically disabled after 10 consecutive failed deliveries (non-2xx responses)." After fixing the cause, re-enable the endpoint in your organization's webhook settings and redeliver failed events from the delivery overview (source).

Check your Polar endpoint in 10 seconds (free).

Paste your webhook URL. WebhookProof sends 3 harmless test requests and tells you whether Polar can reach it and whether it rejects unsigned and forged events. If it finds a problem, the $9 fix pack gives you the exact copy-paste Polar fix for your stack (refundable for 14 days).

Run the free Polar check

FAQ

Which signing scheme does my Polar webhook secret use?

It depends on when the secret was created. Secrets from 8 September 2026, 00:00 UTC onward use Standard Webhooks (pass whsec_ as-is). Older ones use Polar HMAC (base64-encode the full whsec_ string before giving it to a Standard Webhooks library). Polar SDK 1.0.0-alpha.19+ tries both.

Why did svix or standardwebhooks fail on every Polar delivery?

Polar issue #13519 (opened Aug 3, 2026) reported that Polar's key derivation didn't match the Standard Webhooks spec, so generic libraries failed on 100% of deliveries. A maintainer closed it as fixed on Oct 13, 2026.

Why does Polar get a 403 from my endpoint?

Usually your own verifier rejecting the signature, auth middleware covering the webhook route, or Cloudflare Bot Fight Mode. Polar says IP allow lists and WAF rules do not bypass Bot Fight Mode; it must be turned off.

Sources

More guides

Stripe webhook not working? Check these 7 things in order · A customer paid but didn't get access. What went wrong? · No signatures found matching the expected signature for payload · Stripe webhook failing with a 307 or 308 redirect

Last reviewed 2026-10-19. WebhookProof is an independent tool, not affiliated with Polar. Quotes are from the linked documentation.