← Blog

·

Código de verificación (OTP) por WhatsApp con plantilla de autenticación

Actualizado el 25/10/2026

Para enviar un código de verificación (OTP) por WhatsApp, Meta exige una plantilla de autenticación: texto predefinido (del tipo «123456 es tu código de verificación.»), un botón de OTP (copiar código, autocompletar con un toque o zero-tap) y nada de URL, multimedia ni emojis. Creas la plantilla una vez, Meta la aprueba y, en cada inicio de sesión, tu aplicación envía el código como parámetro. Para destinatarios en Brasil, cada mensaje de autenticación entregado cuesta R$ 0,0350 en la tabla en reales vigente desde el 1 de octubre de 2026, con descuentos por volumen; los demás países tienen sus propias tarifas en las tablas de Meta.

Esta guía muestra los tres tipos de botón, los payloads de creación y envío, cómo configurar vencimiento y TTL, y las prácticas de seguridad que recomienda Meta.

Por qué tiene que ser una plantilla de autenticación

Meta es explícita: solo las plantillas de autenticación pueden enviar contraseñas de un solo uso para verificar identidad. Las de marketing y utilidad no pueden. Si Meta detecta una plantilla de otra categoría usada para esto, avisa y cambia su estado a REJECTED el primer día del mes siguiente, sin opción de revisión. Las reglas completas de categoría están en cómo Meta clasifica tu plantilla.

Para clasificarse como autenticación, la plantilla debe:

  • usar las plantillas de autenticación de la Cloud API, con texto fijo definido por Meta;
  • incluir un botón de OTP;
  • no tener URL, multimedia ni emojis, ni en el contenido ni en los parámetros;
  • usar parámetros de hasta 15 caracteres.

Casos de uso aceptados: creación de cuenta, recuperación o integridad del acceso y confirmación de pedidos o transacciones.

El texto es fijo: qué puedes configurar

El cuerpo no lo escribes tú. Meta usa un texto predefinido, traducido al idioma de la plantilla, y ofrece dos complementos opcionales:

OpciónCampoEfecto
Aviso de seguridadadd_security_recommendation: true en el cuerpoAgrega una frase que pide no compartir el código
Vencimiento del códigocode_expiration_minutes en el pie (1 a 90)Agrega en el pie el aviso de que el código vence en N minutos
Tiempo de vida del mensajemessage_send_ttl_seconds (30 a 900)Si no se entrega en ese plazo, el mensaje se descarta

El TTL predeterminado de las plantillas de autenticación es de 10 minutos (las creadas antes del 23 de octubre de 2024 tenían 30 días). Meta recomienda un TTL igual o menor que el vencimiento del código: no tiene sentido entregar un código ya vencido. Como Meta solo cobra los mensajes entregados, los descartados por TTL no se facturan.

¿Quieres probar mientras lees? Crea tu cuenta en Vectalk y envía el primer mensaje por la API oficial. Crear cuenta gratis →

Los tres tipos de botón

TipoCómo funcionaPlataforma¿Requiere integración en la app?
Copiar código (COPY_CODE)El usuario toca el botón, el código va al portapapeles y lo pega en tu appTodasNo
Un toque (ONE_TAP)El botón abre tu app con el código ya completadoAndroidSí: handshake y una activity para recibir el código
Zero-tap (ZERO_TAP)Sin botón: tu app recibe el código por broadcast y el usuario no sale de la pantallaAndroidSí: handshake, broadcast receiver y aceptación de términos

En iOS 26 o superior, el propio teclado sugiere el código recibido en WhatsApp, sin integración. En versiones anteriores de iOS, el usuario ve el botón de copiar código.

Un detalle importante: un toque y zero-tap tienen respaldo. Si no hubo handshake, si la app no coincide o si el destinatario no usa Android, WhatsApp muestra el botón de copiar código (en zero-tap, intenta primero el de un toque). Así, una plantilla de un toque o zero-tap funciona como copiar código en el peor de los casos.

Crear la plantilla con botón de copiar código

Con la Cloud API directa, la plantilla se crea en el endpoint message_templates de la cuenta de WhatsApp Business:

curl -X POST "https://graph.facebook.com/v26.0/TU_WABA_ID/message_templates" \
  -H "Authorization: Bearer TOKEN_DE_META" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "codigo_verificacion",
    "language": "es",
    "category": "AUTHENTICATION",
    "message_send_ttl_seconds": 300,
    "components": [
      { "type": "BODY", "add_security_recommendation": true },
      { "type": "FOOTER", "code_expiration_minutes": 5 },
      {
        "type": "BUTTONS",
        "buttons": [
          { "type": "OTP", "otp_type": "COPY_CODE", "text": "Copiar código" }
        ]
      }
    ]
  }'

Fíjate en que el cuerpo no tiene campo text: lo completa Meta. La etiqueta del botón (text) es opcional y tiene hasta 25 caracteres; sin ella, Meta usa una etiqueta predeterminada traducida. Después de crearla, el botón OTP aparece como tipo URL al consultar la plantilla, y eso es lo esperado.

Variante de un toque (Android)

Para un toque, cambia el botón e indica las apps autorizadas:

{
  "type": "OTP",
  "otp_type": "ONE_TAP",
  "text": "Copiar código",
  "autofill_text": "Autocompletar",
  "supported_apps": [
    { "package_name": "com.ejemplo.app", "signature_hash": "K8a/AINcGX7" }
  ]
}

Reglas del botón de un toque, según la documentación de autocompletar:

  • supported_apps acepta hasta 5 pares de paquete y hash;
  • package_name tiene hasta 224 caracteres, con al menos dos segmentos separados por punto;
  • signature_hash tiene exactamente 11 caracteres;
  • autofill_text y text tienen hasta 25 caracteres;
  • la app debe iniciar un handshake con WhatsApp antes del envío y tener una activity con la acción com.whatsapp.otp.OTP_RETRIEVED;
  • el handshake vale 10 minutos, o el tiempo de code_expiration_minutes, si está definido.

Meta recomienda el SDK oficial para el handshake. El método basado en PendingIntent se descontinúa el 15 de octubre de 2026.

Variante zero-tap (Android)

Zero-tap usa "otp_type": "ZERO_TAP", los mismos supported_apps y el campo zero_tap_terms_accepted: true. Sin esa aceptación, la plantilla no se crea. La app necesita un broadcast receiver para com.whatsapp.otp.OTP_RETRIEVED. Incluso con zero-tap, el usuario ve en WhatsApp el mensaje con el texto fijo.

Para depurar un toque y zero-tap en Android, WhatsApp envía señales de error por broadcast con la acción com.whatsapp.OTP_ERROR, con claves como otp_request_expired y missing_handshake_or_disorder.

Enviar el código

El envío es una plantilla común, con una particularidad: el código aparece dos veces, en el parámetro del cuerpo y en el del botón. El código tiene un máximo de 15 caracteres.

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "5215512345678",
  "type": "template",
  "template": {
    "name": "codigo_verificacion",
    "language": { "code": "es" },
    "components": [
      {
        "type": "body",
        "parameters": [{ "type": "text", "text": "482913" }]
      },
      {
        "type": "button",
        "sub_type": "url",
        "index": "0",
        "parameters": [{ "type": "text", "text": "482913" }]
      }
    ]
  }
}

Una función en Node.js que genera el código, guarda su hash y lo envía:

import crypto from 'node:crypto';

export async function enviarOtp(telefono, db) {
  const codigo = String(crypto.randomInt(0, 1_000_000)).padStart(6, '0');
  const hash = crypto.createHash('sha256').update(codigo).digest('hex');
  await db.guardarOtp(telefono, hash, Date.now() + 5 * 60 * 1000); // 5 minutos

  const cuerpo = {
    messaging_product: 'whatsapp',
    recipient_type: 'individual',
    to: telefono,
    type: 'template',
    template: {
      name: 'codigo_verificacion',
      language: { code: 'es' },
      components: [
        { type: 'body', parameters: [{ type: 'text', text: codigo }] },
        { type: 'button', sub_type: 'url', index: '0', parameters: [{ type: 'text', text: codigo }] },
      ],
    },
  };

  const r = await fetch(process.env.WHATSAPP_URL, {
    method: 'POST',
    headers: { Authorization: `Bearer ${process.env.WHATSAPP_TOKEN}`, 'Content-Type': 'application/json' },
    body: JSON.stringify(cuerpo),
  });
  return r.json(); // guarda el wamid para cruzarlo con el webhook de estado
}

Sigue el estado por el webhook: si el delivered no llega dentro del TTL, considera el mensaje descartado y ofrece otro canal. Los estados posibles están en estado de mensajes por webhook.

Seguridad: lo que recomienda Meta

La página de buenas prácticas de autenticación incluye cuidados que conviene tomar en serio:

  • Números reciclados. WhatsApp solo verifica la titularidad del número en el registro, y un número puede cambiar de dueño. En la Cloud API, guarda el hash de identidad que recibes tras el primer OTP validado e inclúyelo en los envíos siguientes: si el número ahora es de otra persona, la entrega falla en lugar de llegar al nuevo titular.
  • Desafío extra en flujos sensibles. Para recuperar cuentas, combina el código de WhatsApp con otra verificación.
  • Reenvío bloqueado. WhatsApp desactiva el reenvío de mensajes de autenticación, lo que reduce el phishing.
  • Elección de canal. Pide consentimiento y ofrece opciones (WhatsApp, correo, SMS). Confirma qué número usa la persona en WhatsApp, que puede ser distinto del de SMS.
  • WhatsApp instalado. En Android, verifica los paquetes com.whatsapp y com.whatsapp.w4b; en iOS, si se puede abrir el esquema whatsapp://otp.
  • Una cuenta por empresa. Cada empresa necesita su propia cuenta, cuenta de mensajería y número. Compartirlos entre empresas infringe la política.

Cuánto cuesta cada código

Meta cobra la autenticación por mensaje entregado y la tarifa depende del país del destinatario. Para destinatarios en Brasil, la tabla en reales vigente desde el 1 de octubre de 2026 tiene descuentos progresivos por volumen mensual, sumado en todas las cuentas del portafolio:

Mensajes de autenticación por mes (Brasil)Precio por mensaje (BRL)
Hasta 500.000R$ 0,0350
500.001 a 3.000.000R$ 0,0333
3.000.001 a 5.250.000R$ 0,0315
5.250.001 a 10.000.000R$ 0,0298
10.000.001 a 20.000.000R$ 0,0280
Más de 20.000.000R$ 0,0263

Los niveles se reinician cada mes. La tarifa de autenticación internacional, que se cobra en algunos mercados, no se aplica a Brasil. Los mensajes enviados dentro de una ventana de punto de entrada gratuito, abierta por anuncios que hacen clic a WhatsApp, no se cobran. Para simular volúmenes, consulta cuánto cuesta una campaña de WhatsApp.

Cómo hacerlo con Vectalk

En Vectalk, la plantilla de autenticación se crea en POST /api/templates con el mismo cuerpo de Meta, usando un token de instancia:

curl -X POST https://apis.vectalk.com.br/api/templates \
  -H "Authorization: Bearer TU_TOKEN_DE_INSTANCIA" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "codigo_verificacion",
    "language": "es",
    "category": "AUTHENTICATION",
    "components": [
      { "type": "BODY", "add_security_recommendation": true },
      { "type": "FOOTER", "code_expiration_minutes": 5 },
      { "type": "BUTTONS", "buttons": [ { "type": "OTP", "otp_type": "COPY_CODE", "text": "Copiar código" } ] }
    ]
  }'

El envío usa POST https://apis.vectalk.com.br/api/messages con el payload de la sección anterior. En el código Node.js de arriba, basta con apuntar WHATSAPP_URL a ese endpoint y usar el token de Vectalk. Consulta la documentación de plantillas y crea tu cuenta en apps.vectalk.com.br/register.

Preguntas frecuentes

¿Puedo escribir mi propio texto para el código de verificación?

No. El texto de la plantilla de autenticación lo define Meta. Solo eliges el idioma, si incluyes el aviso de seguridad, el vencimiento en minutos y las etiquetas de los botones.

¿El código puede tener letras?

Sí, Meta habla de códigos generalmente alfanuméricos. El límite es de 15 caracteres por parámetro, y el mismo valor va en el cuerpo y en el botón.

¿El botón de un toque funciona en iPhone?

No. Un toque y zero-tap son exclusivos de Android. En iPhone, el usuario ve el botón de copiar código; en iOS 26 o superior, el teclado también sugiere el código automáticamente.

¿Necesito una plantilla distinta para cada idioma?

Sí. Cada idioma es una plantilla. Para crearlas en bloque, el endpoint upsert_message_templates de Meta acepta una lista de idiomas a la vez.

¿Una plantilla de autenticación puede ser rechazada?

Sí, por formato o parámetros inválidos. No se le aplica la regla de duplicados, porque el texto es estándar. Consulta plantilla rechazada en WhatsApp.


Fuentes oficiales consultadas el 25/10/2026: Plantillas de autenticación, Botón de copiar código, Botón de un toque, Zero-tap, Señales de error, Buenas prácticas de autenticación, Time-to-live, Categorización de plantillas, Precios y la hoja «BRL volume tiers» (vigente desde el 1/10/2026).

Prueba hoy la API oficial de WhatsApp

Crea tu cuenta, genera el token y envía el primer mensaje con la guía de la documentación. Los mismos payloads y webhooks de la Cloud API de Meta.