Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversOctober DealsAmazon USOctober deal check: compare before you payAmazon US: current deals, useful picks and tech finds.Check DealsClean PCRecommendedOne scan can reveal what keeps slowing WindowsLook for cleanup and repair opportunities.Run Scan×
Skip to content
World desk6 min

Verifying ElevenLabs Webhook Signatures on Cloudflare Workers Without the SDK

Cloudflare Workers can verify HMAC-SHA256 with native Web Crypto. The critical step is matching the exact ElevenLabs signing contract for your webhook type before parsing the raw request body.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

You can verify an ElevenLabs webhook in a Cloudflare Worker without its SDK by using the Worker’s native Web Crypto API—but only if your verifier matches the signing contract for the specific webhook product. Read the request body as raw bytes, validate the signature header and timestamp, verify the HMAC over the documented input, and parse JSON only after verification. ElevenLabs recommends its SDK verifier for general webhooks; the explicit timestamp.raw_body format described below is documented for Custom Channel replies, so do not assume it applies to every event type.

First confirm which ElevenLabs signing format applies

ElevenLabs’ general Webhooks documentation says webhooks use HMAC authentication and recommends checking the ElevenLabs-Signature header with its SDK. It describes the JavaScript constructEvent and Python construct_event helpers as verifying the signature, validating the timestamp, and parsing JSON. That general section does not specify the complete HMAC input construction.

As an Amazon Associate I earn from qualifying purchases.

ElevenLabs’ Custom Channel guide documents a reply signature shaped like t=1753876800,v0=<hex-digest>. In that Custom Channel reply context, the message authenticated with HMAC-SHA256 is {timestamp}.{raw_request_body}. The guide says to verify the raw body before parsing JSON and to reject stale timestamps. Its exact statement is: “The digest is an HMAC-SHA256 signature over {timestamp}.{raw_request_body} using the outbound signing secret.” This is evidence for Custom Channel replies, not proof that every ElevenLabs webhook has the same header fields or signing input. Check the documentation or SDK behavior for the event type you are integrating before deploying a custom verifier.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Choose between the SDK and a custom Worker verifier

Route When it fits Trade-off
ElevenLabs SDK helper Your runtime and dependency policy allow the SDK, and its helper supports the webhook type you receive. This is the documented default for general webhooks; the helper handles signature verification, timestamp validation, and JSON parsing. Confirm the helper’s compatibility with your product and version.
Worker Web Crypto You need to avoid the SDK and have a confirmed signing contract for the specific webhook. Cloudflare Workers provides the cryptographic primitives, but you own raw-body handling, header parsing, freshness policy, compatibility checks, and maintenance if the provider changes its format.

Cloudflare documents HMAC and SHA-256 support in Workers’ Web Crypto API, along with HMAC key import and HMAC verification. Its guidance warns against naive string comparison of message authentication codes. Using crypto.subtle.verify() avoids implementing a normal string comparison yourself.

#1 Best Overall
Yubico - Security Key C NFC - Basic Compatibility - Multi-Factor authentication (MFA) Security Key and passkey, Connect via USB-C or NFC, FIDO Certified
  • POWERFUL SECURITY KEY: The Security Key C NFC is the essential physical passkey for protecting your digital life from phishing attacks. It ensures only you can access your accounts.
  • WORKS WITH 1000+ ACCOUNTS: Compatible with Google, Microsoft, and Apple. A single Security Key C NFC secures 100 of your favorite accounts, including email, password managers, and more.
  • FAST & CONVENIENT LOGIN: Plug in your Security Key C NFC via USB-C and tap it, or tap it against your phone (NFC) to authenticate. No batteries, no internet connection, and no extra fees required.
  • TRUSTED PASSKEY TECHNOLOGY: Uses the latest passkey standards (FIDO2/WebAuthn & FIDO U2F) but does not support One-Time Passwords. For complex needs, check out the YubiKey 5 Series.
  • BUILT TO LAST: Made from tough, waterproof, and crush-resistant materials. Manufactured in Sweden and programmed in the USA with the highest security standards.

Implement verification without changing the signed bytes

The example below is for a product whose confirmed contract matches the Custom Channel format: a decimal Unix timestamp in seconds, a hexadecimal v0 digest, and HMAC-SHA256 over the UTF-8 bytes of timestamp.raw_body. It uses a 300-second freshness window as an application policy example—not as a universal ElevenLabs requirement. Choose an appropriate tolerance for your deployment and clock-skew conditions.

Set ELEVENLABS_WEBHOOK_SECRET as a protected Worker secret binding, not a source-code constant. For example, configure it with wrangler secret put ELEVENLABS_WEBHOOK_SECRET for the relevant Worker environment. The binding value should be the signing secret for this webhook, not a general API key.

Rank #2
Sale
Thetis Nano-A FIDO2 Security Key Hardware Passkey Device with USB Type A, TOTP/HOTP, FIDO2.0 Two Factor Authentication 2FA MFA, Works with Windows/mac/iOS/Android/Linux/Gmail/Facebook/GitHub/Coinbase
  • Ultra-Compact FIDO2 Security Key - Plug-and-stay or carry on a keychain. This USB-A hardware security key offers portable, always-on protection for desktop and mobile use. (Item Size: 0.75 X 0.74 IN x 0.25 IN)
  • USB-A Hardware Key for All Devices - Works with USB-A ports on PC, Mac, Android, and other laptop/notebook device. Enables secure, cross-platform login with FIDO2.0 passkey support.
  • FIDO Certified Security Key - Meets FIDO and FIDO2 standards. Works with Google, Microsoft, GitHub, Dropbox, and more. Please check service compatibility before purchase.
  • Passwordless Login with Passkey - Supports passkey login via WebAuthn and CTAP2. Enjoy password-free sign-ins where supported. Not all websites or services currently support passkeys.
  • Advanced Multi-Factor Authentication - Offers 200 FIDO2 passkey slots and 50 OATH-TOTP slots. Strong, flexible 2FA/MFA support across various apps and authentication platforms.
const MAX_AGE_SECONDS = 300; // Application policy; choose for your deployment.
const MAX_FUTURE_SKEW_SECONDS = 60; // Application policy; choose for your deployment.

function hexToBytes(hex) {
  if (hex.length === 0 || hex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(hex)) {
    throw new Error("Invalid signature encoding");
  }
  const bytes = new Uint8Array(hex.length / 2);
  for (let i = 0; i < bytes.length; i++) {
    bytes[i] = Number.parseInt(hex.slice(i * 2, i * 2 + 2), 16);
  }
  return bytes;
}

function parseSignature(header) {
  // Reject repeated fields rather than choosing one ambiguously.
  const fields = header.split(",");
  const timestamps = [];
  const digests = [];
  for (const field of fields) {
    const separator = field.indexOf("=");
    if (separator < 1) throw new Error("Malformed signature header");
    const name = field.slice(0, separator).trim();
    const value = field.slice(separator + 1).trim();
    if (name === "t") timestamps.push(value);
    if (name === "v0") digests.push(value);
  }
  if (timestamps.length !== 1 || digests.length !== 1) {
    throw new Error("Missing or duplicate signature fields");
  }
  if (!/^[0-9]+$/.test(timestamps[0])) throw new Error("Invalid timestamp");
  const timestamp = Number(timestamps[0]);
  if (!Number.isSafeInteger(timestamp)) throw new Error("Invalid timestamp");
  return { timestampText: timestamps[0], timestamp, mac: hexToBytes(digests[0]) };
}

async function verifyElevenLabs(request, env) {
  if (request.method !== "POST") {
    return new Response("Method not allowed", { status: 405 });
  }
  const header = request.headers.get("ElevenLabs-Signature");
  if (!header) return new Response("Unauthorized", { status: 401 });

  let parsed;
  try {
    parsed = parseSignature(header);
  } catch {
    return new Response("Unauthorized", { status: 401 });
  }

  const now = Math.floor(Date.now() / 1000);
  if (parsed.timestamp < now - MAX_AGE_SECONDS ||
      parsed.timestamp > now + MAX_FUTURE_SKEW_SECONDS) {
    return new Response("Unauthorized", { status: 401 });
  }

  // Read once, before JSON parsing or any transformation of the body.
  const rawBody = new Uint8Array(await request.arrayBuffer());
  const prefix = new TextEncoder().encode(`${parsed.timestampText}.`);
  const signedMessage = new Uint8Array(prefix.length + rawBody.length);
  signedMessage.set(prefix, 0);
  signedMessage.set(rawBody, prefix.length);

  const secretBytes = new TextEncoder().encode(env.ELEVENLABS_WEBHOOK_SECRET);
  const key = await crypto.subtle.importKey(
    "raw",
    secretBytes,
    { name: "HMAC", hash: "SHA-256" },
    false,
    ["verify"]
  );

  let valid = false;
  try {
    valid = await crypto.subtle.verify("HMAC", key, parsed.mac, signedMessage);
  } catch {
    valid = false;
  }
  if (!valid) return new Response("Unauthorized", { status: 401 });

  let event;
  try {
    event = JSON.parse(new TextDecoder().decode(rawBody));
  } catch {
    return new Response("Invalid JSON", { status: 400 });
  }

  // Validate the expected event shape, then enqueue or process idempotently.
  // Return 200 promptly once the authenticated delivery is safely accepted.
  return new Response("OK", { status: 200 });
}

Adapt the parser to the documented header exactly

The parser deliberately rejects missing, repeated, malformed, or non-numeric timestamp and digest fields. If the webhook’s official contract permits multiple signature versions or defines different formatting, implement that contract explicitly rather than silently accepting extra forms. The digest is decoded from hexadecimal into bytes: passing the ASCII characters of the hex string to verify() would verify the wrong value.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Keep the body byte-for-byte intact

Do not call request.json() and serialize the resulting object again before verification. JSON can be represented with different whitespace, escaping, or byte encodings while expressing the same data; a MAC authenticates bytes, not semantic JSON equivalence. The code reads the body once into a byte array and joins those exact bytes to the timestamp prefix shown in the applicable contract.

Rank #3
FIDO2 U2F Security Key Passkey Two-Factor Authentication (2FA) USB Key PIN+Touch (Non-Biometric) USB-C Type TrustKey T120
  • Security Key : Protect your online accounts against unauthorized access by using FIDO2 and U2F authentication with T120. It's the world's most protective security key that works with windows, Mac OS, Linux as well as Chrome, Firefox, Edge and many other major browsers.
  • Certified with the new FIDO2 standard, T120 provides the benefit of fast login and strong protection against phishing, account takeover as well as many other online attactks.
  • Works with : Bank of America, Github, Google, Microsoft, DUO, Twitter, Facebook, Dropbox, Apple, ebay, BINANCE, mor and more.
  • Fits USB-C port : Insert the T120 security key into the USB-C port of each service and log in conveniently with one touch
  • For the driver download and user guide, please visit TrustKey Solutions Home support page.

Set freshness as your own explicit policy

A valid MAC can still be replayed if an old signed request is accepted indefinitely. The Custom Channel guide says to reject stale timestamps, and ElevenLabs’ general webhook page says its SDK helpers validate timestamps, but the material does not establish one universal freshness window for all webhook types. The sample’s five-minute age and one-minute future-skew values are local policy examples. Consider expected delivery delays and clock synchronization when choosing limits.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Handle authenticated deliveries safely

Authentication establishes that a request matches a secret and signed payload; it does not make event processing automatically safe. Validate the authenticated JSON against the event type you expect, then make side effects idempotent. ElevenLabs notes that retry bodies can be identical to the original and recommends deduplication using event_timestamp and event-specific identifiers such as conversation_id.

Rank #4
Kensington VeriMark NFC+ USB‑C Security Key, FIDO2/WebAuthn Hardware Authenticator for Passwordless Login, Works with Windows, macOS & Chrome OS, K64739WW
  • USB-C or tap via NFC for easy authentication on any compatible device. No drivers needed; optional Kensington software available for advanced management features.
  • Works across Windows, macOS, iOS, Android, ChromeOS, and supports Passkeys and Apple ID.
  • Slim, keychain-ready form for easy carry and on-the-go authentication
  • IP68-rated for dependable performance
  • FIDO CTAP 2.1 for enhanced security features (e.g. resident credentials, Passkey support) and backwards compatibility with CTAP 2. FIDO2 L2 certified security for phishing resistant protection against identity theft and unauthorized access.

Acknowledge promptly after you have safely accepted the authenticated event—often by placing work on a queue—rather than holding the webhook request open for slow downstream work. ElevenLabs says to return HTTP 200 promptly after signature validation; repeated failures can eventually disable a webhook. Its general documentation says disablement occurs at 10 or more consecutive failures if no delivery has ever succeeded or the last successful delivery was more than seven days ago.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

As described in ElevenLabs’ general Webhooks documentation checked on 2026-10-05, retries are disabled by default, can be enabled per webhook, and currently apply only to post_call_transcription webhooks. For retryable failures, the documented schedule is up to five retries: immediate, then 30 seconds, 2 minutes, 8 minutes, and 30 minutes, with up to 10% random jitter. The documented retryable responses are 5xx, 429, and 408; 4xx responses are not retried. These settings and policies can change, so confirm the current behavior for your webhook in your ElevenLabs account and current documentation before depending on it.

Test the verifier against the provider’s contract

Before production, confirm the exact signing input, secret, header encoding, timestamp units, and event type with the documentation or SDK implementation for the webhook you receive. Test both valid and invalid cases using signed fixtures or known-good deliveries, including:

  • A valid signature over the exact raw body and timestamp.
  • A one-byte body change, altered timestamp, malformed hex digest, absent header, and duplicate header fields.
  • A valid signature with a timestamp outside your configured freshness policy.
  • Valid signed JSON with an unexpected event shape, so authentication and application-level validation remain distinct.

The general page currently lists post_call_transcription, voice_removal_notice, voice_removal_notice_withdrawn, and voice_removed as supported event types; treat that list as changeable and verify the events enabled for your account. Never include the webhook secret in logs or error responses.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Leave a Reply

Your email address will not be published. Required fields are marked *

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Crashes, No Sound, or Screen Glitches?Free driver scan
PC Slower Than It Used to Be?Free scan - under a minute

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.