{"id":506,"date":"2026-10-28T16:04:39","date_gmt":"2026-10-28T16:04:39","guid":{"rendered":"https:\/\/vectalk.com.br\/blog\/validar-firma-webhook-whatsapp\/"},"modified":"2026-10-28T16:04:59","modified_gmt":"2026-10-28T16:04:59","slug":"validar-firma-webhook-whatsapp","status":"publish","type":"post","link":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/","title":{"rendered":"C\u00f3mo validar la firma del webhook de WhatsApp (X-Hub-Signature-256)"},"content":{"rendered":"\n<p><em>Actualizado el 28\/10\/2026<\/em><\/p>\n\n\n\n<p>Para validar la firma del webhook de WhatsApp, calcula un HMAC SHA-256 del cuerpo de la solicitud usando como clave el <strong>app secret<\/strong> (clave secreta) de tu app de Meta y comp\u00e1ralo con el encabezado <code>X-Hub-Signature-256<\/code>, que llega con el formato <code>sha256=&lt;hash&gt;<\/code>. Si coinciden, el evento vino de Meta y no fue alterado en el camino. El error que m\u00e1s rompe la validaci\u00f3n es calcular el hash sobre el JSON que tu framework ya interpret\u00f3, y no sobre los bytes exactos que llegaron.<\/p>\n\n\n\n<p>Esta gu\u00eda muestra el paso a paso, c\u00f3digo listo para Node.js (Express), Python (FastAPI y Flask) y PHP, y los errores m\u00e1s comunes. Para el panorama general de la plataforma, consulta nuestra <a href=\"https:\/\/vectalk.com.br\/blog\/es\/whatsapp-cloud-api-es\/\">gu\u00eda de WhatsApp Cloud API<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Por qu\u00e9 validar la firma<\/h2>\n\n\n\n<p>La URL de tu webhook es p\u00fablica. Cualquiera que la descubra puede enviar un <code>POST<\/code> con un JSON con el formato de Meta, simulando el mensaje de un cliente, un bot\u00f3n que confirma un pago o un estado <code>delivered<\/code> que nunca ocurri\u00f3. Sin validaci\u00f3n, tu sistema acepta todo.<\/p>\n\n\n\n<p>La <a href=\"https:\/\/developers.facebook.com\/docs\/graph-api\/webhooks\/getting-started\" target=\"_blank\" rel=\"noreferrer noopener\">documentaci\u00f3n de webhooks de la Graph API<\/a> indica que Meta firma todas las notificaciones con SHA-256 y env\u00eda la firma en el encabezado <code>X-Hub-Signature-256<\/code>, precedida de <code>sha256=<\/code>. Validarla no es obligatorio, pero Meta lo recomienda. En la pr\u00e1ctica, es lo que separa un webhook confiable de un endpoint abierto.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Las dos solicitudes que recibe tu endpoint<\/h2>\n\n\n\n<p>La misma URL recibe dos tipos de llamadas, cada una con su verificaci\u00f3n:<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table><thead><tr><th>Solicitud<\/th><th>Cu\u00e1ndo ocurre<\/th><th>Qu\u00e9 validar<\/th><th>Respuesta<\/th><\/tr><\/thead><tbody><tr><td><code>GET<\/code> de verificaci\u00f3n<\/td><td>Al configurar o cambiar la URL en el panel de la app<\/td><td><code>hub.mode<\/code> igual a <code>subscribe<\/code> y <code>hub.verify_token<\/code> igual al token que definiste<\/td><td><code>200<\/code> con el valor de <code>hub.challenge<\/code><\/td><\/tr><tr><td><code>POST<\/code> de evento<\/td><td>Cada mensaje, estado o cambio en la cuenta<\/td><td><code>X-Hub-Signature-256<\/code> contra el HMAC del cuerpo sin procesar<\/td><td><code>200<\/code> r\u00e1pido; procesamiento en cola<\/td><\/tr><\/tbody><\/table><\/figure>\n\n\n\n<p>Seg\u00fan la p\u00e1gina <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/create-webhook-endpoint\" target=\"_blank\" rel=\"noreferrer noopener\">Create a webhook endpoint<\/a>, si la verificaci\u00f3n es v\u00e1lida respondes <code>200<\/code> con el <code>hub.challenge<\/code>; si no, respondes cualquier cosa distinta de <code>200<\/code> (un 403, por ejemplo). La misma p\u00e1gina exige un certificado TLS v\u00e1lido en el endpoint: no se aceptan certificados autofirmados.<\/p>\n\n\n\n<p>El <em>verify token<\/em> y el <em>app secret<\/em> son cosas distintas. El verify token es una cadena que t\u00fa inventas y registras en el panel; solo sirve para el <code>GET<\/code>. El app secret lo genera Meta, est\u00e1 en <strong>Configuraci\u00f3n de la app &gt; B\u00e1sica<\/strong> y es el que firma los <code>POST<\/code>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Paso a paso de la validaci\u00f3n<\/h2>\n\n\n\n<ol class=\"wp-block-list\">\n<li>Lee el cuerpo de la solicitud <strong>como bytes<\/strong>, antes de cualquier parser de JSON.<\/li>\n\n\n<li>Calcula <code>HMAC-SHA256(clave = app secret, mensaje = cuerpo sin procesar)<\/code> y convi\u00e9rtelo a hexadecimal.<\/li>\n\n\n<li>Arma <code>sha256=<\/code> + hash y comp\u00e1ralo con el encabezado <code>X-Hub-Signature-256<\/code> usando una comparaci\u00f3n de tiempo constante.<\/li>\n\n\n<li>Si no coincide, responde 401 o 403 y descarta el evento.<\/li>\n\n\n<li>Si coincide, interpreta el JSON, pon el evento en una cola y responde <code>200<\/code>.<\/li>\n\n<\/ol>\n\n\n\n<p>La comparaci\u00f3n de tiempo constante (<code>crypto.timingSafeEqual<\/code>, <code>hmac.compare_digest<\/code>, <code>hash_equals<\/code>) evita que un atacante adivine el hash byte por byte midiendo el tiempo de respuesta.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Ejemplo en Node.js con Express<\/h2>\n\n\n\n<p>La clave es usar <code>express.raw()<\/code> en la ruta del webhook, para que <code>req.body<\/code> sea un <code>Buffer<\/code> con los bytes originales:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-js\">import express from 'express';\nimport crypto from 'node:crypto';\n\nconst app = express();\nconst APP_SECRET = process.env.META_APP_SECRET;\nconst VERIFY_TOKEN = process.env.WEBHOOK_VERIFY_TOKEN;\n\n\/\/ GET de verificaci\u00f3n\napp.get('\/webhook', (req, res) =&gt; {\n  const mode = req.query['hub.mode'];\n  const token = req.query['hub.verify_token'];\n  const challenge = req.query['hub.challenge'];\n  if (mode === 'subscribe' &amp;&amp; token === VERIFY_TOKEN) {\n    return res.status(200).send(challenge);\n  }\n  return res.sendStatus(403);\n});\n\n\/\/ POST de eventos: cuerpo sin procesar solo en esta ruta\napp.post('\/webhook', express.raw({ type: 'application\/json' }), (req, res) =&gt; {\n  const recibida = req.get('X-Hub-Signature-256') || '';\n  const esperada = 'sha256=' + crypto\n    .createHmac('sha256', APP_SECRET)\n    .update(req.body)\n    .digest('hex');\n\n  const a = Buffer.from(recibida);\n  const b = Buffer.from(esperada);\n  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {\n    return res.sendStatus(401);\n  }\n\n  const evento = JSON.parse(req.body.toString('utf8'));\n  res.sendStatus(200);\n  colaDeEventos.push(evento); \/\/ procesa fuera del ciclo de la solicitud\n});\n\napp.use(express.json()); \/\/ las dem\u00e1s rutas pueden usar JSON normalmente\napp.listen(3000);<\/code><\/pre>\n\n\n\n<p>Si tu app ya declara <code>app.use(express.json())<\/code> antes de esta ruta, el cuerpo llega interpretado y el hash no coincide. Hay dos salidas: declarar la ruta del webhook antes del middleware global o guardar los bytes en el propio <code>express.json<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-js\">app.use(express.json({\n  verify: (req, _res, buf) =&gt; { req.rawBody = buf; },\n}));\n\/\/ luego usa req.rawBody en createHmac<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ejemplo en Python con FastAPI<\/h2>\n\n\n\n<p>En FastAPI, <code>await request.body()<\/code> devuelve los bytes exactos. No firmes el modelo Pydantic del cuerpo:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-python\">import hashlib\nimport hmac\nimport json\nimport os\n\nfrom fastapi import FastAPI, HTTPException, Request, Response\n\napp = FastAPI()\nAPP_SECRET = os.environ[\"META_APP_SECRET\"].encode()\nVERIFY_TOKEN = os.environ[\"WEBHOOK_VERIFY_TOKEN\"]\n\n\n@app.get(\"\/webhook\")\nasync def verificar(request: Request):\n    p = request.query_params\n    if p.get(\"hub.mode\") == \"subscribe\" and p.get(\"hub.verify_token\") == VERIFY_TOKEN:\n        return Response(content=p.get(\"hub.challenge\", \"\"), media_type=\"text\/plain\")\n    raise HTTPException(status_code=403)\n\n\n@app.post(\"\/webhook\")\nasync def recibir(request: Request):\n    cuerpo = await request.body()\n    recibida = request.headers.get(\"x-hub-signature-256\", \"\")\n    esperada = \"sha256=\" + hmac.new(APP_SECRET, cuerpo, hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(recibida, esperada):\n        raise HTTPException(status_code=401)\n\n    evento = json.loads(cuerpo)\n    # encola el evento y responde r\u00e1pido\n    return {\"ok\": True}<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ejemplo en Python con Flask<\/h2>\n\n\n\n<p>En Flask, usa <code>request.get_data()<\/code>, que devuelve el cuerpo sin procesar:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-python\">import hashlib\nimport hmac\nimport os\n\nfrom flask import Flask, abort, request\n\napp = Flask(__name__)\nAPP_SECRET = os.environ[\"META_APP_SECRET\"].encode()\n\n\n@app.post(\"\/webhook\")\ndef recibir():\n    cuerpo = request.get_data()\n    recibida = request.headers.get(\"X-Hub-Signature-256\", \"\")\n    esperada = \"sha256=\" + hmac.new(APP_SECRET, cuerpo, hashlib.sha256).hexdigest()\n    if not hmac.compare_digest(recibida, esperada):\n        abort(401)\n    evento = request.get_json()\n    return \"\", 200<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Ejemplo en PHP<\/h2>\n\n\n\n<p>En PHP, el cuerpo sin procesar viene de <code>php:\/\/input<\/code>. Cuidado con el <code>GET<\/code>: PHP reemplaza los puntos por guiones bajos en los nombres de par\u00e1metros, as\u00ed que <code>hub.verify_token<\/code> se convierte en <code>$_GET['hub_verify_token']<\/code>.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-php\">&lt;?php\n$appSecret = getenv('META_APP_SECRET');\n$verifyToken = getenv('WEBHOOK_VERIFY_TOKEN');\n\nif ($_SERVER['REQUEST_METHOD'] === 'GET') {\n    if (($_GET['hub_mode'] ?? '') === 'subscribe'\n        &amp;&amp; hash_equals($verifyToken, $_GET['hub_verify_token'] ?? '')) {\n        echo $_GET['hub_challenge'] ?? '';\n        exit;\n    }\n    http_response_code(403);\n    exit;\n}\n\n$cuerpo = file_get_contents('php:\/\/input');\n$recibida = $_SERVER['HTTP_X_HUB_SIGNATURE_256'] ?? '';\n$esperada = 'sha256=' . hash_hmac('sha256', $cuerpo, $appSecret);\n\nif (!hash_equals($esperada, $recibida)) {\n    http_response_code(401);\n    exit;\n}\n\n$evento = json_decode($cuerpo, true);\nhttp_response_code(200);<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Errores comunes que hacen que la firma no coincida<\/h2>\n\n\n\n<p><strong>Hash calculado sobre el JSON interpretado.<\/strong> Es el error n\u00famero uno. <code>JSON.stringify(req.body)<\/code> o <code>json.dumps(payload)<\/code> generan un texto distinto del original: cambian espacios, orden de claves y escape de caracteres. Un solo byte distinto cambia todo el hash. Firma siempre los bytes que llegaron.<\/p>\n\n\n\n<p><strong>Codificaci\u00f3n equivocada.<\/strong> Convertir el cuerpo a texto con un charset incorrecto (latin-1 en vez de UTF-8, por ejemplo) altera nombres con tilde y emojis. Trabaja con bytes hasta terminar la validaci\u00f3n.<\/p>\n\n\n\n<p><strong>Secret equivocado.<\/strong> El valor correcto es el app secret de la app suscrita al webhook. No es el token de acceso, ni el verify token, ni el secret de otra app del mismo portafolio. Si tienes apps separadas para pruebas y producci\u00f3n, cada entorno necesita el suyo.<\/p>\n\n\n\n<p><strong>Prefijo ignorado.<\/strong> El encabezado trae <code>sha256=<\/code> antes del hash. O comparas la cadena completa (como en los ejemplos) o quitas el prefijo de ambos lados.<\/p>\n\n\n\n<p><strong>Middleware o gateway que altera el cuerpo.<\/strong> Proxies, gateways de API y funciones serverless a veces reformatean o codifican el cuerpo antes de entregarlo a tu c\u00f3digo. Si la validaci\u00f3n falla solo en producci\u00f3n, registra el tama\u00f1o del cuerpo recibido y comp\u00e1ralo con el <code>Content-Length<\/code>.<\/p>\n\n\n\n<p><strong>Secret cambiado sin actualizar el servidor.<\/strong> Al restablecer el app secret en el panel, los eventos pasan a llegar firmados con el nuevo valor. Si tu servidor rechaza todo con 401, Meta reintenta: seg\u00fan la <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">descripci\u00f3n general de webhooks<\/a>, las entregas que no reciben <code>200<\/code> se repiten con frecuencia decreciente durante hasta 7 d\u00edas, lo que puede generar eventos duplicados. Monitorea la tasa de 401 del endpoint para detectarlo a tiempo.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Buenas pr\u00e1cticas despu\u00e9s de validar<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Responde r\u00e1pido.<\/strong> Valida, encola y devuelve <code>200<\/code>. El trabajo pesado (IA, CRM, base de datos) va a un worker.<\/li>\n\n\n<li><strong>Maneja duplicados.<\/strong> Usa el <code>id<\/code> del mensaje (<code>wamid<\/code>) o del estado como clave de idempotencia, ya que los reintentos pueden repetir eventos.<\/li>\n\n\n<li><strong>Acepta payloads grandes.<\/strong> La descripci\u00f3n general de webhooks indica que un payload puede tener hasta 3 MB; revisa el l\u00edmite de cuerpo de tu servidor.<\/li>\n\n\n<li><strong>No dependas de listas de IP.<\/strong> Meta cambia sus direcciones peri\u00f3dicamente y sugiere mTLS en su lugar.<\/li>\n\n\n<li><strong>Prueba localmente<\/strong> con un t\u00fanel antes de desplegar; mira <a href=\"https:\/\/vectalk.com.br\/blog\/es\/probar-webhook-whatsapp-localmente\/\">c\u00f3mo probar el webhook de WhatsApp con ngrok<\/a>.<\/li>\n\n<\/ul>\n\n\n\n<p>Para enviar un evento firmado a tu propio entorno de prueba, calcula el hash con el mismo secret:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code class=\"language-bash\">cuerpo='{\"object\":\"whatsapp_business_account\",\"entry\":[]}'\nfirma=$(printf '%s' \"$cuerpo\" | openssl dgst -sha256 -hmac \"$META_APP_SECRET\" | sed 's\/^.* \/\/')\ncurl -X POST http:\/\/localhost:3000\/webhook \\\n  -H \"Content-Type: application\/json\" \\\n  -H \"X-Hub-Signature-256: sha256=$firma\" \\\n  -d \"$cuerpo\"<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">C\u00f3mo hacerlo con Vectalk<\/h2>\n\n\n\n<p>Vectalk es un proxy de la Cloud API oficial: el Hub recibe los eventos de Meta y reenv\u00eda a las URL que registras el mismo payload de la documentaci\u00f3n de Meta, sin formato propio. Puedes registrar las URL que necesites por instancia con <code>POST https:\/\/apis.vectalk.com.br\/api\/webhooks<\/code>, y tu endpoint debe responder <code>200<\/code> en menos de 20 segundos, seg\u00fan la <a href=\"https:\/\/docs.vectalk.com.br\/concepts\/webhooks\">documentaci\u00f3n de webhooks de Vectalk<\/a>. El encabezado <code>X-Hub-Signature-256<\/code> descrito aqu\u00ed es el que Meta env\u00eda a quien recibe directamente desde la app; para saber c\u00f3mo autenticar la entrega que hace el Hub en tu caso, consulta la documentaci\u00f3n o habla con el equipo en la <a href=\"https:\/\/vectalk.com.br\/contato.html\">p\u00e1gina de contacto<\/a>. El parser del payload, la cola y la idempotencia no cambian. Para empezar, crea tu cuenta en <a href=\"https:\/\/apps.vectalk.com.br\/register\">apps.vectalk.com.br\/register<\/a>.<\/p>\n\n\n\n<p>Con el webhook protegido, los siguientes pasos naturales son <a href=\"https:\/\/vectalk.com.br\/blog\/es\/descargar-multimedia-webhook-whatsapp\/\">descargar los archivos que env\u00eda el cliente<\/a> y controlar el ritmo de respuesta para no chocar con el <a href=\"https:\/\/vectalk.com.br\/blog\/es\/limite-mensajes-por-segundo-api-whatsapp\/\">throughput y el rate limit de la API<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Preguntas frecuentes<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfD\u00f3nde encuentro el app secret?<\/h3>\n\n\n\n<p>En el panel de desarrolladores de Meta, en <strong>Configuraci\u00f3n de la app &gt; B\u00e1sica<\/strong>, campo &#8220;Clave secreta de la app&#8221;. Gu\u00e1rdalo en una variable de entorno o en un gestor de secretos, nunca en el repositorio.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfEl verify token debe ser igual al app secret?<\/h3>\n\n\n\n<p>No, y no deber\u00eda. El verify token es una cadena que eliges y solo sirve para el <code>GET<\/code> de verificaci\u00f3n. El app secret lo genera Meta y firma los eventos <code>POST<\/code>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfPor qu\u00e9 pasa la verificaci\u00f3n GET y falla la firma del POST?<\/h3>\n\n\n\n<p>Porque son verificaciones independientes. El <code>GET<\/code> solo compara el verify token. Cuando el <code>POST<\/code> falla, casi siempre el hash se calcula sobre el JSON interpretado o con el secret de otra app.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfQu\u00e9 c\u00f3digo debo devolver si la firma es inv\u00e1lida?<\/h3>\n\n\n\n<p>Cualquier c\u00f3digo distinto de <code>200<\/code>, como 401 o 403. Recuerda que las entregas leg\u00edtimas rechazadas se reintentan, as\u00ed que un secret desactualizado aparece como una avalancha de 401 y de eventos atrasados.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">\u00bfNecesito validar la firma en el entorno de pruebas?<\/h3>\n\n\n\n<p>S\u00ed. Validar desde el primer d\u00eda evita que llegue a producci\u00f3n c\u00f3digo sin verificaci\u00f3n. Para probar sin Meta, genera la firma con <code>openssl<\/code> como en el ejemplo anterior. Los detalles del payload est\u00e1n en <a href=\"https:\/\/vectalk.com.br\/blog\/es\/estado-mensaje-webhook-whatsapp\/\">estado de mensajes v\u00eda webhook<\/a>.<\/p>\n\n\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n\n\n<p><strong>Fuentes oficiales consultadas el 28\/10\/2026:<\/strong> <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/create-webhook-endpoint\" target=\"_blank\" rel=\"noreferrer noopener\">Create a webhook endpoint (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/documentation\/business-messaging\/whatsapp\/webhooks\/overview\" target=\"_blank\" rel=\"noreferrer noopener\">WhatsApp webhooks: descripci\u00f3n general (Meta)<\/a>, <a href=\"https:\/\/developers.facebook.com\/docs\/graph-api\/webhooks\/getting-started\" target=\"_blank\" rel=\"noreferrer noopener\">Webhooks de la Graph API: getting started (Meta)<\/a>, <a href=\"https:\/\/docs.vectalk.com.br\/concepts\/webhooks\">Webhooks en la documentaci\u00f3n de Vectalk<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>C\u00f3mo verificar el encabezado X-Hub-Signature-256 del webhook de la API de WhatsApp con HMAC SHA-256, con c\u00f3digo en Node.js, Python y PHP y los errores que la rompen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_post_was_ever_published":false},"categories":[12],"tags":[],"class_list":["post-506","post","type-post","status-publish","format-standard","hentry","category-uncategorized-es"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Firma del webhook de WhatsApp: X-Hub-Signature-256<\/title>\n<meta name=\"description\" content=\"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Firma del webhook de WhatsApp: X-Hub-Signature-256\" \/>\n<meta property=\"og:description\" content=\"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/\" \/>\n<meta property=\"og:site_name\" content=\"Blog Vectalk\" \/>\n<meta property=\"article:published_time\" content=\"2026-10-28T16:04:39+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-28T16:04:59+00:00\" \/>\n<meta name=\"author\" content=\"wanderleyfcunha\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"wanderleyfcunha\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/\"},\"author\":{\"name\":\"wanderleyfcunha\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"headline\":\"C\u00f3mo validar la firma del webhook de WhatsApp (X-Hub-Signature-256)\",\"datePublished\":\"2026-10-28T16:04:39+00:00\",\"dateModified\":\"2026-10-28T16:04:59+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/\"},\"wordCount\":1454,\"inLanguage\":\"en-US\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/\",\"name\":\"Firma del webhook de WhatsApp: X-Hub-Signature-256\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\"},\"datePublished\":\"2026-10-28T16:04:39+00:00\",\"dateModified\":\"2026-10-28T16:04:59+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\"},\"description\":\"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/es\\\/validar-firma-webhook-whatsapp\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"C\u00f3mo validar la firma del webhook de WhatsApp (X-Hub-Signature-256)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/\",\"name\":\"Blog Vectalk\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/vectalk.com.br\\\/blog\\\/#\\\/schema\\\/person\\\/ff36ecd9d8257856f227f8e5d639db2b\",\"name\":\"wanderleyfcunha\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g\",\"caption\":\"wanderleyfcunha\"},\"sameAs\":[\"https:\\\/\\\/vectalk.com.br\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Firma del webhook de WhatsApp: X-Hub-Signature-256","description":"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/","og_locale":"en_US","og_type":"article","og_title":"Firma del webhook de WhatsApp: X-Hub-Signature-256","og_description":"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.","og_url":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/","og_site_name":"Blog Vectalk","article_published_time":"2026-10-28T16:04:39+00:00","article_modified_time":"2026-10-28T16:04:59+00:00","author":"wanderleyfcunha","twitter_card":"summary_large_image","twitter_misc":{"Written by":"wanderleyfcunha","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/#article","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/"},"author":{"name":"wanderleyfcunha","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"headline":"C\u00f3mo validar la firma del webhook de WhatsApp (X-Hub-Signature-256)","datePublished":"2026-10-28T16:04:39+00:00","dateModified":"2026-10-28T16:04:59+00:00","mainEntityOfPage":{"@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/"},"wordCount":1454,"inLanguage":"en-US"},{"@type":"WebPage","@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/","url":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/","name":"Firma del webhook de WhatsApp: X-Hub-Signature-256","isPartOf":{"@id":"https:\/\/vectalk.com.br\/blog\/#website"},"datePublished":"2026-10-28T16:04:39+00:00","dateModified":"2026-10-28T16:04:59+00:00","author":{"@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b"},"description":"Valida la firma del webhook de WhatsApp: HMAC SHA-256 del cuerpo sin procesar con el app secret, con ejemplos en Node.js, Python y PHP y errores comunes.","breadcrumb":{"@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/vectalk.com.br\/blog\/es\/validar-firma-webhook-whatsapp\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/vectalk.com.br\/blog\/"},{"@type":"ListItem","position":2,"name":"C\u00f3mo validar la firma del webhook de WhatsApp (X-Hub-Signature-256)"}]},{"@type":"WebSite","@id":"https:\/\/vectalk.com.br\/blog\/#website","url":"https:\/\/vectalk.com.br\/blog\/","name":"Blog Vectalk","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/vectalk.com.br\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/vectalk.com.br\/blog\/#\/schema\/person\/ff36ecd9d8257856f227f8e5d639db2b","name":"wanderleyfcunha","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/21c37077f1731eb558973f27a7b647d55f72fde5200a843ac5f5345b247ea725?s=96&d=mm&r=g","caption":"wanderleyfcunha"},"sameAs":["https:\/\/vectalk.com.br\/blog"]}]}},"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/506","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/comments?post=506"}],"version-history":[{"count":1,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/506\/revisions"}],"predecessor-version":[{"id":509,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/posts\/506\/revisions\/509"}],"wp:attachment":[{"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/media?parent=506"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/categories?post=506"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/vectalk.com.br\/blog\/wp-json\/wp\/v2\/tags?post=506"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}