Saltar al contenido

API Oficial (CALLING)

Contexto

WhatsApp Business Calling agrega el canal de comunicación VoIP además de la mensajería de texto entre consumidores y empresas. Los consumidores usan la aplicación de WhatsApp como en las llamadas entre consumidores, mientras que la empresa interactúa con la API de WhatsApp a través de la Graph API para la señalización y conexión inicial de la llamada.

Los endpoints de llamadas preservan los campos de usuario nuevos (BSUID) cuando Meta los requiere o los entrega en el payload. Para el detalle completo, consulta Business-scoped user IDs (BSUID).

Propuesta de valor

WhatsApp Business Calling permite a las empresas iniciar y recibir llamadas con usuarios de WhatsApp usando Voz sobre Protocolo de Internet (VoIP), con alcance global.

ValorDescripción
Comunicación unificadaMensajería y llamadas desde un mismo número, en todo el mundo.
Marca y confianzaIdentidad de marca integrada, verificación y disponibilidad global.
Relación con el clienteUn único punto de contacto para comunicación entrante y saliente.
Ventas y soporteUnifica los canales de marketing y soporte en un solo lugar.
Funciones enriquecidasVideo*, compartir pantalla* y personalización de llamadas.
Desvío de llamadasMueve las llamadas de voz al chat de WhatsApp.
Conveniencia del clienteGratis para tus clientes y disponible globalmente.
RegistroUn hilo único con un registro centralizado de largo plazo.

Nota: * Funcionalidad planificada o en desarrollo. Consulta con tu contacto de Meta o partner para más detalles.

Arquitectura

Configuraciones posibles de señalización y media

Configuración por defectoSIP con WebRTCSIP con media SDES
Protocolo de señalizaciónGraph APIs + WebhooksSIP (requiere habilitación explícita)SIP (requiere habilitación explícita)
Transporte de señalizaciónHTTPSTLSTLS
Protocolo de mediaWebRTC (ICE + DTLS + SRTP)WebRTC (ICE + DTLS + SRTP)SDES SRTP (requiere habilitación explícita)
Códec de audioOPUSOPUSOPUS

Notas:

  1. También puedes usar SDES en lugar de ICE+DTLS con señalización Graph API + Webhooks.
  2. Códecs de audio adicionales soportados: PCMA, PCMU.

Comenzar

Requisitos previos

  1. Tu número de negocio debe estar en uso con Cloud API (no la app de WhatsApp Business).
  2. Suscribe tu app al campo de webhook calls (a menos que planees usar SIP).
  3. La misma app debe estar suscrita a la cuenta de WhatsApp Business de tu número de teléfono.
  4. La app debe tener permisos de mensajería (whatsapp_business_messaging) para el número de negocio.
  5. El negocio debe tener un límite de mensajería diario de al menos 2,000 destinatarios únicos.
  6. Habilita las funciones de llamadas en tu número de teléfono de negocio.

Configurar las funciones de llamadas

La API ofrece funciones que afectan cuándo y cómo aparecen las funciones de llamada a los usuarios en tu perfil de WhatsApp:

  • Control de llamadas entrantes: permite evitar que los usuarios realicen llamadas desde tu perfil de negocio.
  • Horario de llamadas del negocio: evita llamadas perdidas y dirige a los usuarios a mensajear cuando tu centro de llamadas está cerrado.
  • Solicitudes de callback: ofrecen al usuario la opción de solicitar un callback cuando no respondes o si tu centro de llamadas está cerrado.

Hacer y recibir llamadas

Cloud API Calling ofrece dos rutas de inicio de llamadas:

  • Llamadas iniciadas por el usuario: llamadas realizadas desde un usuario de WhatsApp a tu negocio.
  • Llamadas iniciadas por el negocio: llamadas realizadas desde tu negocio a un usuario de WhatsApp.

Pruebas y cuentas sandbox

Advertencia: las cuentas sandbox solo están disponibles para Tech Partners.

Información general

Una cuenta sandbox de WhatsApp es una cuenta de WhatsApp Business simulada que puedes usar para probar tu integración con la Calling API. Usa una cuenta sandbox de calling para probar lo siguiente:

  • Iniciar y recibir llamadas con la Calling API.
  • Validar eventos de webhook de llamadas.
  • Simular flujos de onboarding sin crear activos de negocio reales.

Límites de llamadas de las cuentas sandbox

Los siguientes límites corresponden a las cuentas sandbox. Están sujetos a cambios.

LímiteDescripciónLímite de número de producciónLímite de número de prueba público
Límite de llamadas conectadasCantidad de llamadas que un negocio puede realizar con permisos aprobados.100 llamadas conectadas por 24 hSin cambios
Límites de mensajes de solicitud de permiso de llamadaLimita la cantidad de mensajes de solicitud de permiso de llamada que se pueden enviar al mismo consumidor1 solicitud por día

2 solicitudes por semana
25 solicitudes por día

100 solicitudes por semana
Límites de llamadas sin respuestaCuando el usuario rechaza o pierde una llamada iniciada por el negocio.Aviso en 2 llamadas consecutivas sin respuesta

Revocación del permiso en 4 llamadas consecutivas sin respuesta
Aviso en 5 llamadas consecutivas sin respuesta

Revocación en 10 llamadas consecutivas sin respuesta
Duración temporal de llamadasDuración durante la cual un negocio puede llamar al usuario tras la aprobación del permiso.7 díasSin cambios

Configurar una cuenta sandbox

Paso 1. Reclamar una cuenta sandbox

Sigue las instrucciones en Embedded Signup Overview — Claiming sandbox accounts para reclamar tu cuenta sandbox.

Paso 2. Obtener credenciales e identificadores de tu cuenta sandbox

  1. En el App Dashboard, navega a tu app y selecciona WhatsApp > Embedded Signup Builder en la barra lateral.
    • Nota: mantén esta pestaña abierta, la usarás varias veces durante este proceso.
  2. Asegúrate de que el menú desplegable Features esté vacío y haz clic en Login with Facebook.
  3. Se mostrará un popup con la experiencia de Embedded Signup. En Business portfolio, selecciona Sandbox Business.
  4. Completa el resto de la información requerida y haz clic en Next.
  5. En la siguiente pantalla, en el menú desplegable Create or Select a WhatsApp Business Profile, selecciona Test Number.
  6. Cuando el flujo de login finalice, en la sección Exchange Token, haz clic en Get Token.
    • Nota: conserva este token para el uso futuro de la API de la cuenta sandbox.
  7. En la sección Fetch Shared WhatsApp Business account, haz clic en Fetch WABA details.
  8. En el campo WhatsApp Business account, copia el Value de la fila id.
    • Nota: conserva este ID, es el ID de la cuenta de WhatsApp Business para la WABA sandbox.
  9. En la sección Fetch phone numbers, haz clic en Fetch phone numbers.
  10. En ID, copia el valor.
    • Nota: conserva este ID, es el ID de número de teléfono del número de prueba de tu cuenta sandbox.

Paso 3. Registrar tu número de teléfono de prueba y suscribirte a tu WABA

Prerrequisitos

Asegúrate de tener la siguiente información de los pasos anteriores:

  • El token de tu cuenta sandbox
  • El ID de WABA de tu cuenta sandbox
  • El ID de tu número de teléfono de prueba

Para completar estos pasos usarás la herramienta Graph API Explorer.

  • Nota: mantén esta ventana abierta, ya que usarás la configuración creada más adelante en esta guía.
  1. Navega a la herramienta Graph API Explorer.
  2. Asegúrate de estar en la última versión de la API.
  3. Haz clic en Generate Access Token y sigue las indicaciones.
  4. En Permissions, agrega los permisos whatsapp_business_management y whatsapp_business_messaging.
  5. En el constructor de endpoints, ingresa /<YOUR_SANDBOX_WABA_ID>/subscribed_apps y haz clic en Submit.
{
  "success": true
}
  1. A continuación, registra tu número de teléfono de prueba ingresando /<YOUR_SANDBOX_TEST_PHONE_NUMBER_ID>/register en el constructor de endpoints.
  2. En la barra lateral izquierda, haz clic en JSON, ingresa el siguiente cuerpo JSON y haz clic en Submit:
{
  "messaging_product": "whatsapp",
  "pin": "123456"
}
  1. Deberías recibir una respuesta estándar success:
{
  "success": true
}

Paso 4. Probar tu funcionalidad de mensajería

  1. En la herramienta Graph API Explorer, ingresa /<YOUR_SANDBOX_TEST_PHONE_NUMBER_ID>/messages en el constructor de endpoints.
  2. En la barra lateral izquierda, haz clic en JSON, ingresa el siguiente cuerpo JSON y haz clic en Submit:
{
  "messaging_product": "whatsapp",
  "to": "YOUR_NUMBER", // Reemplaza este valor con el número de teléfono de tu dispositivo.
  "recipient": "US.13491208655302741918",
  "type": "template",
  "template": {
    "name": "hello_world",
    "language": { "code": "en_US" }
  }
}

Nota: Usernames e IDs de usuario con ámbito de negocio: el campo recipient te permite identificar al usuario de WhatsApp por su BSUID en lugar de, o además de, su número de teléfono en to. Para más detalles, consulta Business-scoped user IDs.

  1. Recibirás una respuesta con el valor "message_status": "accepted" y deberías recibir un mensaje de texto en tu dispositivo.

Paso 5. Configurar webhooks y permisos

  • Navega al App Dashboard.
  • Haz clic en la app que usas con WhatsApp.
  • Selecciona Use cases (ícono de lápiz) en la barra lateral.
  • En Connect with customers through WhatsApp, haz clic en Customize.
  • En la barra lateral izquierda, haz clic en Configuration.
  • En Callback URL, agrega la URL de callback de tu servidor de webhooks.
  • En Verify token, agrega una cadena de verificación arbitraria.
  • Haz clic en Verify and save.
  • En la siguiente página, en el menú desplegable Select product, haz clic en WhatsApp Business Account.
  • En Webhook fields, en la fila calls, haz clic en el toggle para suscribirte al campo de webhook calls.

Finalizar: habilitar las funciones de llamada en tu número de teléfono de prueba

  1. En la herramienta Graph API Explorer, ingresa /<YOUR_SANDBOX_TEST_PHONE_NUMBER_ID>/settings en el constructor de endpoints.
  2. En la barra lateral izquierda, haz clic en JSON, ingresa el siguiente cuerpo JSON y haz clic en Submit:
{
  "calling": {
    "status": "ENABLED",
    "call_icon_visibility": "DEFAULT",
    "callback_permission_status": "ENABLED"
  }
}
  1. Deberías recibir una respuesta estándar success:
{
  "success": true
}
  1. Finalmente, en Access Token, copia el access token para uso futuro.
    • Nota: conserva este access token, lo usarás para hacer llamadas a la API para probar tu integración con la Calling API.

Probar las llamadas iniciadas por el negocio

Antes de poder probar las llamadas iniciadas por el negocio (BIC), debes otorgar permisos de llamada de usuario a tu cuenta sandbox.

Puedes hacerlo en el dispositivo cliente que usas para las pruebas:

  1. En tu dispositivo cliente, abre WhatsApp.
  2. Navega al hilo de mensajes que tienes con tu número de teléfono de negocio sandbox.
  3. En la parte superior de la pantalla, toca el número de teléfono de negocio sandbox.
  4. Desplázate hacia abajo y toca Business Calling Permission.
  5. Toca Allow calls.

Ahora puedes usar tu integración de Calling API para llamar al dispositivo cliente y probar tu integración.

Más información sobre las llamadas iniciadas por el negocio.

Probar las llamadas iniciadas por el usuario

Puedes probar las llamadas iniciadas por el usuario (UIC) en el dispositivo cliente que usas para las pruebas:

  1. En tu dispositivo cliente, abre WhatsApp.
  2. Navega al hilo de mensajes que tienes con tu número de teléfono de negocio sandbox.
  3. Toca el ícono de teléfono en la parte superior de la pantalla para llamar al número de teléfono de negocio sandbox.
  4. Confirma que la llamada se conecta correctamente.

Más información sobre las llamadas iniciadas por el usuario.

Disponibilidad

Llamadas iniciadas por el usuario

Disponibles en todas las ubicaciones donde Cloud API está disponible.

Llamadas iniciadas por el negocio

Disponibles en todas las ubicaciones donde Cloud API está disponible, excepto en los siguientes países:

  • Estados Unidos
  • Canadá
  • Egipto
  • Vietnam
  • Nigeria

Nota: el código de país del número de teléfono del negocio debe estar en esta lista soportada. El número del consumidor puede ser de cualquier país donde Cloud API esté disponible.

Changelog

FechaTítuloDescripción
23 de marzo de 2026Soporte de códec de audio G.711 (PCMA, PCMU)Nueva sección para la configuración del códec de audio G.711 (PCMA, PCMU) en los ajustes de llamadas.
27 de enero de 2026Restricciones de llamadas basadas en feedback de usuariosSe aplican nuevas restricciones de llamadas basadas en el feedback de los usuarios.
19 de diciembre de 2025Actualización del límite de llamadas iniciadas por el negocioEl número de llamadas iniciadas por el negocio por usuario aumentó a 100 por día (desde 10 por día).
10 de diciembre de 2025Introducción de restrict_to_user_countries para el ícono de llamadaAhora puedes controlar en qué países debe ser visible el ícono de llamada.
13 de octubre de 2025Actualización del límite de llamadas iniciadas por el negocioEl número de llamadas iniciadas por el negocio por usuario aumentó a 10 por día (desde 5 por día). Se agregó la sección “Pruebas y cuentas sandbox”.
29 de septiembre de 2025Guía de integración con AsteriskNueva guía para integrar con Asterisk.
24 de septiembre de 2025Propagación de contexto desde botones de llamada y deep linksEspecifica una cadena opaca en botones de llamada o deep links para rastrear el origen de las llamadas iniciadas por el usuario.
8 de septiembre de 2025Actualización de la API de estado de salud para llamadasLa API de Health Status ahora incluye el campo can_receive_call_sip para diagnosticar problemas de configuración SIP.
5 de septiembre de 2025Restricciones de llamadas por baja tasa de respuestaRestricciones por baja tasa de respuesta de llamadas en vigor.
21 de julio de 2025Webhooks de actualización de ajustesRecibe webhooks cuando los ajustes se actualizan.

Configuración de llamadas

Utiliza estas APIs para ver y gestionar la configuración de llamadas de los números de teléfono de tu empresa. Por defecto, las llamadas no están habilitadas en un número de teléfono del negocio.

Actualizar configuración

Actualiza la configuración de llamadas de un número de teléfono: habilita o deshabilita la función, controla la visibilidad del ícono, define el horario de atención y las anulaciones por días festivos.

Endpoint: POST /calls/{v}/{did}/settings

Request:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/settings' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "calling": {
      "status": "ENABLED",
      "call_icon_visibility": "DEFAULT",
      "call_icons": {
        "restrict_to_user_countries": ["US", "BR"]
      },
      "call_hours": {
        "status": "ENABLED",
        "timezone_id": "America/Manaus",
        "weekly_operating_hours": [
          {
            "day_of_week": "MONDAY",
            "open_time": "0400",
            "close_time": "1020"
          },
          {
            "day_of_week": "TUESDAY",
            "open_time": "0108",
            "close_time": "1020"
          }
        ],
        "holiday_schedule": [
          {
            "date": "2026-01-01",
            "start_time": "0000",
            "end_time": "2359"
          }
        ]
      },
      "callback_permission_status": "ENABLED",
      "sip": {
        "status": "ENABLED",
        "servers": [
          {
            "hostname": "sip.example.com",
            "port": 5061,
            "request_uri_user_params": {
              "KEY1": "VALUE1"
            }
          }
        ]
      },
      "audio": {
        "additional_codecs": ["PCMA", "PCMU"]
      },
      "voicemail": {
        "status": "ENABLED",
        "triggers": ["REJECT", "TIMEOUT"],
        "audio": {
          "default": {
            "announcement_media_id": 938884519013664,
            "timeout_seconds": 20
          }
        }
      }
    }
  }'

Response (200):

{
  "success": true
}

Parámetros del nodo calling:

CampoRequeridoDescripción
statusENABLED o DISABLED. Indica si la función de llamadas está habilitada para el número.
call_icon_visibilityNoDEFAULT o DISABLE_ALL. Controla la visualización del ícono de llamada en las aplicaciones cliente. Deshabilitar la visibilidad no impide que el usuario haga llamadas no solicitadas al negocio.
call_iconsNoRestringe en qué países se muestra el ícono de llamada.
call_icons.restrict_to_user_countriesNoLista de códigos de país de dos letras (ej. ["US", "BR"]). Vacía = sin restricción. Aplica a todos los usuarios con número registrado en esos países, sin importar su ubicación física.
call_hoursNoHorario de llamadas aplicado a todas las llamadas entrantes. Reemplaza por completo la configuración previa.
call_hours.statusENABLED o DISABLED. Si se deshabilita, el negocio está disponible las 24 horas los 7 días.
call_hours.timezone_idZona horaria del negocio. Consulta las zonas soportadas.
call_hours.weekly_operating_hoursHorario de atención por día (day_of_week, open_time, close_time en formato de 24 horas, ej. "0000" = 12 AM). Máximo 2 entradas por día, sin horarios superpuestos.
call_hours.holiday_scheduleNoAnulaciones al horario semanal (date en AAAA-MM-DD, start_time, end_time). Hasta 20 entradas. Si no se envía, el horario festivo existente se borra.
callback_permission_statusNoENABLED, DISABLED o NOT_SET. Permite que WhatsApp solicite permiso de llamada tras una llamada iniciada por el usuario (conectada o perdida).
ip_addressesNoLista de direcciones IP de los servidores SIP o media del negocio para el allowlisting en el firewall de Meta.
srtp_key_exchange_protocolNoDTLS (default) o SDES. Configura el protocolo de intercambio de claves SRTP.
sipNoConfigura la señalización por SIP. Cuando SIP está habilitado, no puedes usar los endpoints de llamadas ni recibir webhooks de llamadas.
audioNoConfigura los códecs de audio adicionales. Opus es el códec por defecto y siempre está presente.
audio.additional_codecsNoPCMA (G.711 A-law) y/o PCMU (G.711 µ-law). Opus no puede eliminarse.
voicemailNoConfigura la recolección de buzón de voz para llamadas iniciadas por el usuario perdidas o rechazadas.
voicemail.statusENABLED o DISABLED (default). Requiere que las llamadas estén habilitadas en el número.
voicemail.triggersSegún statusREJECT (rechazas la llamada) y/o TIMEOUT (no aceptas ni rechazas dentro de timeout_seconds). Al menos uno cuando está habilitado.
voicemail.audio.defaultSegún statusConfiguración de audio por defecto. announcement_media_id es el ID de un media subido con use_case=call_voicemail_announcement (audio/ogg, OPUS, < 60 seg). timeout_seconds (0-30) aplica solo al trigger TIMEOUT.

Nota sobre la propagación de la configuración: después de actualizar la configuración, los usuarios de WhatsApp pueden tardar hasta 7 días en reflejar los cambios. La mayoría refresca mucho antes. Puedes forzar un refresco inmediato abriendo el chat del negocio y la página de información. Independientemente del comportamiento del cliente, el servidor siempre respeta la configuración.

Comportamiento de la visibilidad del ícono:

  • DEFAULT: el ícono de llamada se muestra en todos los puntos de entrada (menú del chat e información del negocio).

Visibilidad del ícono de llamada (DEFAULT)

  • DISABLE_ALL: el ícono se oculta en el menú del chat y en la ventana de información del negocio. Todos los puntos de entrada externos al chat también se desactivan. Aún puedes enviar mensajes interactivos o plantillas con un botón de llamada (Call CTA).

Visibilidad del ícono de llamada (DISABLE_ALL)

  • Horario de llamadas (call_hours): las llamadas fuera del horario configurado (o dentro de los períodos de vacaciones/indisponibilidad) se bloquean. La pantalla de error del cliente muestra la opción de chatear con el negocio, solicitar una devolución de llamada (si está habilitada) y el próximo horario disponible.

Horario de llamadas

  • Permisos de devolución de llamada (callback_permission_status): una llamada iniciada por la empresa requiere permisos explícitos del usuario. La cuenta puede configurarse para activar automáticamente la interfaz de solicitud de permiso tras una llamada iniciada por el usuario que no haya sido respondida. El usuario puede modificar su selección en cualquier momento.

Permisos de devolución de llamada

Permisos de devolución de llamada (interfaz)

  • Cambio planificado (ETA junio 2025) — permisos proactivos: la aplicación cliente enviará automáticamente un permiso de llamada aprobado cuando el usuario inicie una llamada a la empresa, independientemente del resultado. El usuario podrá modificar esta selección en cualquier momento. Este cambio es transparente desde el punto de vista de la integración.

Permisos proactivos de devolución de llamada

Errores:

CódigoCaso
400Estado inválido, horario inválido, fecha festiva pasada, zona horaria inválida o formato inválido
403Permisos o autorización insuficientes

Obtener configuración

Endpoint: GET /calls/{v}/{did}/settings

Opcionalmente, puedes incluir las credenciales SIP en la respuesta con el query param include_sip_credentials=true:

GET /calls/{v}/{did}/settings?include_sip_credentials=true

Response (200):

{
  "calling": {
    "status": "ENABLED",
    "call_icon_visibility": "DEFAULT",
    "callback_permission_status": "ENABLED",
    "call_hours": {
      "status": "ENABLED",
      "timezone_id": "America/Manaus",
      "weekly_operating_hours": [
        {
          "day_of_week": "MONDAY",
          "open_time": "0400",
          "close_time": "1020"
        }
      ],
      "holiday_schedule": []
    },
    "sip": {
      "status": "ENABLED",
      "servers": [
        {
          "hostname": "sip.example.com",
          "sip_user_password": "{SIP_USER_PASSWORD}"
        }
      ]
    },
    "audio": {
      "additional_codecs": ["PCMA", "PCMU"]
    },
    "voicemail": {
      "status": "ENABLED",
      "triggers": ["REJECT", "TIMEOUT"],
      "audio": {
        "default": {
          "announcement_media_id": 938884519013664,
          "timeout_seconds": 20
        }
      }
    }
  }
}

Response con restricciones: si tu negocio tiene restricciones aplicadas, la respuesta incluye el objeto restrictions:

{
  "calling": {
    "status": "ENABLED",
    "restrictions": {
      "restrictions_list": [
        {
          "type": "RESTRICTED_BUSINESS_INITIATED_CALLING",
          "reason": "Business initiated calling capability has been temporarily disabled for this phone number due to high negative feedback from users.",
          "expiration": 1754072386
        }
      ]
    }
  }
}

Los valores posibles de type son RESTRICTED_BUSINESS_INITIATED_CALLING o RESTRICTED_USER_INITIATED_CALLING. expiration es la marca de tiempo Unix UTC en que expira la restricción.

Buzón de voz (voicemail)

Cuando el buzón de voz está habilitado, Cloud API:

  1. Espera el retraso configurado o una señal de rechazo tuya.
  2. Responde automáticamente la llamada.
  3. Reproduce un anuncio de audio.
  4. Graba el mensaje de voz del llamador.
  5. Entrega el buzón como mensaje de audio vía webhook.

Nota: cuando el buzón de voz está habilitado, desactiva el horario de llamadas (call_hours), porque los usuarios de WhatsApp no pueden llamar fuera del horario comercial. Las llamadas deben estar habilitadas en el número para que la configuración de voicemail tenga efecto.

Subir el media del anuncio

Los archivos de anuncio del buzón de voz deben subirse por la Media Upload API con use_case=call_voicemail_announcement, lo que los exime del TTL de 30 días estándar:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/{v}/{did}/media' \
  --header 'Authorization: Bearer <token>' \
  -F 'file=@<FILE_PATH>;type=audio/ogg' \
  -F 'messaging_product=whatsapp' \
  -F 'use_case=call_voicemail_announcement' \
  -F 'description="Default announcement (English)"'

Requisitos del media: duración menor a 60 segundos, MIME audio/ogg con códec OPUS. Los media subidos con este use_case solo pueden usarse como anuncio de buzón de voz, no como mensaje regular.

Webhooks de buzón de voz

Cuando un usuario deja un mensaje de voz, Cloud API entrega el audio por el campo de webhook messages como un mensaje de audio entrante. La diferencia con un mensaje de audio regular: messages[].id contiene el ID de la llamada (WACID) que produjo el buzón, no un WAMID. Usa ese ID para correlacionar el buzón con el ciclo de vida de la llamada.

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<WABA_ID>",
      "changes": [
        {
          "field": "messages",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "phone_number_id": "<BUSINESS_PHONE_NUMBER_ID>",
              "display_phone_number": "<BUSINESS_PHONE_NUMBER>"
            },
            "contacts": [
              {
                "wa_id": "<USER_PHONE_NUMBER>",
                "profile": { "name": "<USER_PROFILE_NAME>" }
              }
            ],
            "messages": [
              {
                "id": "wacid.HBgLMTQxMjYxMzYyASG...",
                "from": "<USER_PHONE_NUMBER>",
                "timestamp": "1728932177",
                "type": "audio",
                "audio": {
                  "id": "1002764438271669",
                  "sha256": "Y9vvGyeo3n76ptkXu3CwDBsnzbRFqpjHskQdMGSVqas=",
                  "mime_type": "audio/ogg; codecs=opus"
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

La entrega es best-effort: si falla la recolección, no se envía webhook de buzón para esa llamada. No requiere suscripción adicional más allá del campo messages estándar.

Webhooks de actualización de ajustes

Suscríbete al campo de webhook account_settings_update para recibir notificaciones sobre actualizaciones de los ajustes del número. Actualmente solo se observan cambios en los campos de llamadas: status, call_icon_visibility, callback_permission_status, sip.status y srtp_key_exchange_protocol.

Requisitos: suscríbete al campo account_settings_update, la app debe estar suscrita a la WABA del número, y tener permiso whatsapp_business_management.

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "whatsapp-business-account-id",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "timestamp": "1671644824",
            "type": "phone_number_settings",
            "phone_number_settings": {
              "phone_number_id": "phone-number-id",
              "calling": {
                "status": "ENABLED",
                "call_icon_visibility": "DEFAULT",
                "callback_permission_status": "ENABLED"
              }
            }
          },
          "field": "account_settings_update"
        }
      ]
    }
  ]
}

Restricciones de llamadas por feedback de usuarios

Si tus llamadas reciben feedback negativo alto (bloqueos y reportes), la funcionalidad de llamadas iniciadas por el negocio, por el usuario, o ambas, puede restringirse.

Advertencia temprana

Se notifica cuando el número está cerca de ser pausado, vía email y webhook account_update:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "0",
      "time": 1623862418,
      "changes": [
        {
          "field": "account_update",
          "value": {
            "phone_number": "PN",
            "event": "ACCOUNT_VIOLATION",
            "violation_info": {
              "violation_type": "LOW_BUSINESS_INITIATED_CALLING_QUALITY"
            }
          }
        }
      ]
    }
  ]
}

Pausa de la funcionalidad

Cuando el feedback negativo alcanza el umbral, Cloud API restringe automáticamente la funcionalidad por 7 días. Mientras está pausada:

  • Llamadas iniciadas por el negocio: no puede hacer llamadas al usuario ni enviar solicitudes de permiso.
  • Llamadas iniciadas por el usuario: no puede recibir llamadas ni mostrar el ícono de llamada.

Los permisos aprobados o rechazados por los usuarios mientras está pausado siguen siendo válidos.

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "0",
      "time": 1641848059,
      "changes": [
        {
          "field": "account_update",
          "value": {
            "phone_number": "PN",
            "event": "ACCOUNT_RESTRICTION",
            "restriction_info": [
              {
                "restriction_type": "RESTRICTED_BUSINESS_INITIATED_CALLING",
                "expiration": 1641848057
              }
            ]
          }
        }
      ]
    }
  ]
}

Restricciones por baja tasa de respuesta

Cuando las llamadas entrantes no se responden con frecuencia, se notifica y el ícono de llamada puede ocultarse.

Advertencia: email con opciones para cambiar cómo manejas las llamadas entrantes.

Restricción: si la situación persiste, el botón de llamada se oculta de los usuarios. Para mitigarlo: identifica la causa de las llamadas no respondidas y asegura recursos suficientes, o desactiva los botones / las llamadas por WhatsApp Manager.

Webhook de advertencia:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "0",
      "time": 1641848059,
      "changes": [
        {
          "field": "account_update",
          "value": {
            "phone_number": "16505552771",
            "event": "ACCOUNT_VIOLATION",
            "violation_info": {
              "violation_type": "USER_INITIATED_CALLS_LOW_PICKUP_RATE",
              "remediation": "Please identify and address the cause of user-initiated calls not being picked up."
            }
          }
        }
      ]
    }
  ]
}

Webhook de restricción:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "0",
      "time": 1641848059,
      "changes": [
        {
          "field": "account_update",
          "value": {
            "phone_number": "16505552771",
            "event": "ACCOUNT_RESTRICTION",
            "restriction_info": [
              {
                "restriction_type": "RESTRICTED_USER_INITIATED_CALLING_CALL_BUTTON_HIDDEN",
                "remediation": "The call button has been hidden due to low pickup rates."
              }
            ]
          }
        }
      ]
    }
  ]
}

Llamadas iniciadas por el consumidor

La API de Calling soporta recibir llamadas realizadas por usuarios de WhatsApp a tu negocio. Tu negocio determina cuándo pueden recibirse llamadas configurando el horario de llamadas y la indisponibilidad por días festivos.

El flujo de una llamada iniciada por el usuario es:

  1. El usuario llama a tu negocio — recibes el webhook Connect con un SDP Offer.
  2. Pre-aceptar (recomendado) — establece la conexión de media antes de enviar media, lo que evita el recorte de audio.
  3. Aceptar — una vez que la conexión WebRTC está establecida, acepta la llamada. Los medios fluyen inmediatamente tras el 200 OK.
  4. Terminar — tu negocio o el usuario pueden colgar. Recibes el webhook Terminate.

Dispones de aproximadamente 30 a 60 segundos tras el webhook Connect para responder. Si tu negocio no responde, la llamada se termina en el lado del usuario con una notificación “No respondida” y se te envía un webhook de terminación.

Elegibilidad de dispositivos del consumidor: la API de Calling puede aceptar llamadas desde el teléfono primario del consumidor y desde dispositivos acompañantes iPhone y Android. Un dispositivo primario es el dispositivo principal del usuario (típicamente un teléfono móvil) con el estado autoritativo de la cuenta. Los dispositivos acompañantes son dispositivos adicionales registrados en la cuenta (web, desktop, tablets, gafas inteligentes); solo los teléfonos iPhone y Android son soportados para llamadas iniciadas por el usuario. La funcionalidad de callback permission no está soportada en dispositivos acompañantes.

Pre-aceptación

Responder a una llamada iniciada por el usuario mediante la pre-aceptación. Facilita la configuración de la llamada y evita el recorte de audio: establece la conexión WebRTC antes de aceptar la llamada, sin transmitir medios.

Endpoint: POST /calls/{v}/{did}/signaling

Request:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
  "action": "pre_accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  }
}

Response (200):

{
  "messaging_product": "whatsapp",
  "success": true
}

Aceptar

Acepta una llamada previa pre-aceptada, proporcionando el SDP del agente. La empresa dispone de un tiempo determinado (30–60 segundos) para responder a la llamada del usuario; si no responde, la llamada finaliza con “No respondida” y se envía un webhook de finalización.

Endpoint: POST /calls/{v}/{did}/signaling

Request:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
  "action": "accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "biz_opaque_callback_data": "random data"
}

Response (200):

{
  "messaging_product": "whatsapp",
  "success": true
}

Rechazar

Rechaza una llamada iniciada por el usuario.

Endpoint: POST /calls/{v}/{did}/signaling

Request:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
  "action": "reject"
}

Response (200):

{
  "messaging_product": "whatsapp",
  "success": true
}

Colgar

Finaliza una llamada en curso. Debe invocarse incluso si hay un paquete RTCP BYE en la ruta de medios, para obtener precios más precisos. Cuando el consumidor finaliza la llamada, no es necesario invocar esta API; se enviará un webhook de finalización.

Endpoint: POST /calls/{v}/{did}/signaling

Request:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
  "action": "terminate"
}

Response (200):

{
  "messaging_product": "whatsapp",
  "success": true
}

Campos comunes del body de signaling:

CampoRequeridoDescripción
call_idID de la llamada recibido previamente en el webhook.
actionpre_accept, accept, reject o terminate.
sessionSegún la acciónInformación de conexión de la sesión. Requiere sdp_type y sdp. El SDP debe cumplir con RFC 8866.
biz_opaque_callback_dataNoCadena arbitraria para seguimiento, incluida en los webhooks posteriores. Máximo 512 caracteres.

Llamadas a webhooks

Los webhooks de llamadas usan una estructura similar a la de mensajería. Una sección calls dentro de la sección value del webhook contiene los campos relacionados con las llamadas.

Conectar

Se envía en tiempo casi real cuando la empresa recibe una llamada entrante, e incluye la información SDP para establecer la conexión WebRTC.

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "whatsapp-business-account-id",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "16315553601",
              "phone_number_id": "phone-number-id"
            },
            "contacts": [
              {
                "profile": {
                  "name": "callee name",
                  "username": "<USERNAME>"
                },
                "wa_id": "16315553602",
                "user_id": "<BSUID>",
                "parent_user_id": "<PARENT_BSUID>"
              }
            ],
            "calls": [
              {
                "id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
                "to": "16315553601",
                "to_user_id": "<BSUID>",
                "to_parent_user_id": "<PARENT_BSUID>",
                "from": "16315553602",
                "event": "connect",
                "timestamp": "1671644824",
                "direction": "BUSINESS_INITIATED",
                "connection": {
                  "webrtc": {
                    "sdp": "<<RFC 8866 SDP>>"
                  }
                },
                "session": {
                  "sdp_type": "offer",
                  "sdp": "<<RFC 8866 SDP>>"
                }
              }
            ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}

Campos del objeto calls:

CampoDescripción
idID único creado para la llamada.
toDestinatario de la llamada. Puede omitirse si el usuario adoptó un username y no se puede incluir el número.
to_user_idBSUID del usuario de WhatsApp.
to_parent_user_idParent BSUID del usuario. Solo si los parent BSUID están habilitados.
fromLlamador de la llamada. Puede omitirse si el usuario adoptó un username.
from_user_idBSUID del llamador (para llamadas iniciadas por el usuario).
from_parent_user_idParent BSUID del llamador. Solo si los parent BSUID están habilitados.
eventEvento sobre el que notifica el webhook.
timestampMarca de tiempo del evento.
directionBUSINESS_INITIATED o USER_INITIATED.
deeplink_payloadCadena arbitraria del query param biz_payload de un call deeplink. Solo si la llamada se inició desde un deeplink con ese parámetro.
cta_payloadCadena arbitraria del campo payload de un botón de llamada. Solo si la llamada se inició desde un botón con payload.
connectionInformación de conexión WebRTC. connection.webrtc.sdp es el SDP del otro extremo.
sessionInformación de conexión de la sesión; contiene sdp y sdp_type.
sdpDatos del protocolo de descripción de sesión del otro extremo. Debe cumplir con RFC 8866.
sdp_typeTipo de SDP: offer para llamadas iniciadas por el usuario, answer para las iniciadas por la empresa.
contactsPerfil del destinatario: profile.name, profile.username (opcional), wa_id (puede omitirse), user_id (BSUID), parent_user_id (opcional).

Terminada

Se envía cuando la llamada ha sido terminada por cualquier razón (consumidor cuelga o la empresa invoca terminate).

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "whatsapp-business-account-id",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "16505553602",
              "phone_number_id": "phone-number-id"
            },
            "calls": [
              {
                "id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
                "to": "16315553601",
                "from": "16315553602",
                "event": "terminate",
                "direction": "BUSINESS_INITIATED",
                "biz_opaque_callback_data": "random data",
                "timestamp": "1671644824",
                "status": "COMPLETED",
                "start_time": "1671644824",
                "end_time": "1671644944",
                "duration": 120
              }
            ],
            "errors": [
              {
                "code": 222,
                "message": "ERROR_TITLE",
                "href": "ERROR_HREF",
                "error_data": {
                  "details": "ERROR_DETAILS"
                }
              }
            ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}

Campos relevantes:

CampoDescripción
directionDirección de la llamada respecto del negocio.
statusCOMPLETED (completada, incluye rechazada por el destinatario) o FAILED (falló a mitad de conexión).
start_time / end_timeHora de inicio y fin de la llamada. Solo aparecen si la otra persona contestó.
durationDuración en segundos. Solo aparece si la otra persona contestó.
errorsDetalles del error cuando el estado es FAILED.
biz_opaque_callback_dataSolo disponible si se proporcionó en la solicitud de llamada.

Mensajes con CTA de llamada

Después de adoptar las funciones de Calling, puedes crear conciencia en tus clientes de dos maneras:

  • Enviarles un mensaje con un botón de llamada de WhatsApp.
  • Incrustar un deep link de llamada en tus superficies de marca (sitio web, aplicación, etc.).

Enviar mensaje interactivo con botón de llamada

Envía un mensaje interactivo con el botón de llamada de WhatsApp durante una ventana de atención al cliente o una conversación abierta. Cuando el usuario hace clic en el botón, se inicia una llamada de WhatsApp al número del negocio que envió el mensaje.

Endpoint: POST /{v}/{did}/messages

Request:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "14085551234",
  "recipient": "US.13491208655302741918",
  "type": "interactive",
  "interactive": {
    "type": "voice_call",
    "body": {
      "text": "You can call us on WhatsApp now for faster service!"
    },
    "action": {
      "name": "voice_call",
      "parameters": {
        "display_text": "Call on WhatsApp",
        "ttl_minutes": 100,
        "payload": "payload data"
      }
    }
  }
}

Reglas:

  • interactive.type debe ser voice_call y interactive.body es obligatorio.
  • interactive.footer no está permitido.
  • to es requerido (salvo recipient); recipient (BSUID o parent BSUID) puede usarse en su lugar o además. Si se envían ambos, to tiene prioridad.
  • display_text por defecto es Call now; longitud máxima de 20 caracteres.
  • ttl_minutes (opcional): tiempo de vida del botón, entre 1 y 43200 (30 días). Por defecto 10080 (7 días).
  • payload (opcional): cadena arbitraria para tracking. Se incluye en los webhooks connect y terminate bajo el campo cta_payload. Máximo 512 caracteres. Solo disponible para clientes de WhatsApp desde la versión 2.25.27.
  • Enviar este mensaje a usuarios en versiones antiguas genera un webhook de error con código 131026.

Mensaje interactivo con botón de llamada

Crear plantilla con botón de llamada

La API de plantillas soporta el botón VOICE_CALL, que activa una llamada de WhatsApp al hacer clic. Se puede usar en cualquier lugar donde sea posible el botón de número de teléfono.

Endpoint: POST /message_templates/{v}/{did}

Request:

{
  "name": "<NAME>",
  "category": "<CATEGORY>",
  "language": "<LANGUAGE>",
  "components": [
    {
      "type": "BODY",
      "text": "You can call us on WhatsApp now for faster service!"
    },
    {
      "type": "BUTTONS",
      "buttons": [
        {
          "type": "voice_call",
          "text": "Call Now",
          "ttl_minutes": 1440
        },
        {
          "type": "URL",
          "text": "Contact Support",
          "url": "https://www.example.com/support"
        }
      ]
    }
  ]
}

Reglas del botón voice_call en plantillas:

  • type debe ser voice_call.
  • text (opcional): la etiqueta del botón. Por defecto Call Now; máx 20 caracteres.
  • ttl_minutes (opcional): tiempo de vida del botón, entre 1440 (1 día) y 43200 (30 días). Puedes sobrescribirlo al enviar el mensaje.
  • No está soportado en plantillas de carrusel, autenticación, catálogo, cupón, oferta por tiempo limitado, SPM o MPM.

Plantilla con botón de llamada

Enviar plantilla con botón de llamada

Envía la plantilla con botón de llamada a un usuario. Puedes sobrescribir ttl_minutes y enviar un payload de tracking.

Endpoint: POST /{v}/{did}/messages

Request:

{
  "to": "14085551234",
  "recipient": "US.13491208655302741918",
  "messaging_product": "whatsapp",
  "type": "template",
  "recipient_type": "individual",
  "template": {
    "name": "wa_voice_call",
    "language": {
      "code": "en"
    },
    "components": [
      {
        "type": "button",
        "sub_type": "voice_call",
        "parameters": [
          {
            "type": "ttl_minutes",
            "ttl_minutes": 100
          },
          {
            "type": "payload",
            "payload": "payload data"
          }
        ]
      }
    ]
  }
}

Parámetros del componente button:

CampoDescripción
ttl_minutesTiempo de vida del botón, entre 1 y 43200 (30 días). Default 10080 (7 días).
payloadCadena arbitraria para tracking. Se incluye en los webhooks connect y terminate bajo cta_payload. Máximo 512 caracteres. Solo disponible para clientes desde la versión 2.25.27.

Calling deep links

Los deep links de llamada son hipervínculos que enrutan a los usuarios de WhatsApp para llamar a tu negocio. El proceso es similar a un chat deep link, excepto que el formato es:

wa.me/call/<BUSINESS_PHONE_NUMBER>

Nota: los deep links no son soportados en los clientes de escritorio de WhatsApp.

  • Incrustar deep links: úsalos para promocionar las llamadas de WhatsApp en tu sitio web, aplicación principal o un código QR.
  • Enviar deep links: puedes enviar mensajes a usuarios con un deep link de llamada. Como los deep links pueden generarse por número de negocio, puedes usarlos para dirigir a los usuarios a un número diferente con voz habilitada. El formato wa.me/call/<BUSINESS_PHONE_NUMBER> es fácil de copiar, pegar y enviar, y no requiere crear una plantilla.
  • Enviar payload en un deep link: puedes enviar un payload con el query string biz_payload:
wa.me/call/<BUSINESS_PHONE_NUMBER>?biz_payload=payload

Cuando un usuario llama usando el deep link con biz_payload, cualquier app suscrita al campo calls puede obtener este string en los webhooks connect y terminate bajo el campo deeplink_payload. El payload del deep link solo está disponible para clientes de WhatsApp desde la versión 2.25.27.

Códigos de error de llamadas

La mayoría de los errores tienen la siguiente forma:

{
  "error": {
    "message": "<Error Message>",
    "type": "<Exception Type>",
    "code": <Exception Code>,
    "fbtrace_id": "<Trace ID>"
  }
}
CódigoDescripciónPosible soluciónHTTP
100Parámetro inválido en la llamada a la API.Revisa error_data para conocer el detalle exacto. Si es un error de validación SDP, el problema exacto se incluye en los detalles.400
613Límite de la API de estado de permiso de llamada alcanzado.Reintenta más tarde o reduce la frecuencia de solicitudes.429
131009No se admite el tipo de mensaje interactivo voice_call. Tipos soportados [button, list].Verifica que el remitente esté en uno de los países soportados.400
131030El número de teléfono del receptor no está en la lista permitida. Aplica a llamadas y solicitudes de permiso, solo con números de prueba públicos (PTNs).Agrega el número del receptor a la lista permitida y reintenta.400
131044Error de pago en llamadas iniciadas por el usuario.Adjunta un método de pago válido.400
131055Método no permitido. Las llamadas Graph API no están permitidas para números con SIP habilitado.Usa SIP para números habilitados con SIP.400
138000Llamadas no habilitadas para este número de teléfono.Configura los ajustes de llamadas para habilitar las funciones.401
138001El receptor no puede recibir llamadas (no es WhatsApp, no aceptó términos o usa un cliente no compatible).Confirma con el destinatario que usa la última versión de WhatsApp y aceptó la comunicación.400
138002Límite de llamadas simultáneas alcanzado (1000 máximas) para el número.Reintenta más tarde o reduce la frecuencia de llamadas.429
138003Llamada duplicada: ya hay una llamada en curso con el receptor.Reintenta cuando finalice la llamada actual.400
138004Error al conectar la llamada.Reintenta o revisa los parámetros de conexión.500
138005Límite de velocidad de llamadas excedido.Reintenta más tarde o reduce la frecuencia.429
138006No se encontró ningún permiso de llamada aprobado.Asegura que el consumidor aceptó el permiso de llamada.401
138007La llamada no se conectó por tiempo de espera.Aplica la oferta/respuesta SDP de Cloud API a tiempo.500
138009Límite de solicitudes de permiso de llamada alcanzado.Una llamada conectada con el consumidor restablece los límites.400
138012Límite de llamadas iniciadas por empresas en 24 horas alcanzado (100 llamadas conectadas).Revisa error_data para el detalle, incluye un timestamp de cuándo se permite la próxima llamada.400
138013Las llamadas iniciadas por el negocio no están disponibles para este número.Confirma que business-initiated calling está disponible en tu ubicación.400
138014Llamadas temporalmente deshabilitadas por baja calidad.Asegura que tu alcance a los usuarios sea valioso y no spam. Reintenta tras que se levanten las restricciones.400
138015Las llamadas no pueden habilitarse para este número.Verifica que el límite de mensajería del número sea 2000 o más.400
138017La solicitud de permiso no puede enviarse porque ya existe un permiso permanente aprobado por el usuario.No es necesario enviar solicitudes de permiso.400
138018WhatsApp Business calling no puede habilitarse porque no se cumplen los pre-requisitos técnicos.Configura SIP o asegura que haya al menos una app suscrita a la WABA que también esté suscrita al campo calls.400
138019Falló la configuración de la llamada (cliente). Se envía en el webhook de terminación.Reintenta más tarde.400
138020Falló la conexión con el servidor relay (cliente). Se envía en el webhook de terminación.Reintenta más tarde.400
138021Timeout de recepción de media: el cliente terminó por no recibir media por mucho tiempo.Confirma que la media se envía al relay y reintenta.400
138022Timeout de transmisión de media: el cliente terminó por no transmitir media por mucho tiempo.Reintenta más tarde.400
138023Llamada aceptada pero terminada sin señales de conexión de media. Cloud API no pudo determinar si la llamada se conectó.Reintenta más tarde.400

Soporte DTMF

Cloud API soporta tonos DTMF para integrar sistemas IVR. Los consumidores presionan botones en la aplicación cliente y los tonos se inyectan en el flujo RTP de WebRTC establecido como parte de la conexión VoIP.

  • El flujo WebRTC cumple con RFC 4733 para la transferencia de dígitos DTMF sobre RTP.
  • No existe un webhook para transmitir dígitos DTMF.
  • El teclado de marcación solo admite casos de uso DTMF; no cambia ningún otro comportamiento de llamadas.
  • Los valores de los tonos son dígitos del 0 al 9, # y *. La duración es de 500 ms y el intervalo entre tonos de 100 ms.

Clock rate: solo se soporta el clock rate 8000 en los SDP. Para llamadas iniciadas por el usuario, la oferta SDP incluye solo clock rate 8000. Para llamadas iniciadas por el negocio, tu oferta SDP debe usar clock rate 8000; incluso si está ausente, la API procede con 8000 contra el payload type 126. Los paquetes RTP de DTMF usan la misma base de timestamp y secuencia que los paquetes de audio regulares (no hay que preocuparse por clock rates distintos). El campo duration del paquete DTMF se calcula usando unidades de 8000 clock. La API no soporta clock rate 48000 para DTMF.

Teclado de marcación DTMF en la aplicación cliente

Llamadas iniciadas por la empresa

Resumen del producto

La API de Calling permite a tu negocio llamar a los usuarios de WhatsApp. El usuario controla cuándo tu negocio puede llamarle otorgando permisos de llamada a tu número de negocio.

El flujo de una llamada iniciada por el negocio es:

  1. Obtener permiso del usuario para llamarle (mensaje de solicitud de permiso o callback_permission_status habilitado).
  2. Iniciar la llamada con action: connect, identificando al usuario por número (to), BSUID (recipient) o ambos.
  3. Establecer la conexión: recibes el webhook Connect con un SDP Answer de Cloud API y lo aplicas a tu stack WebRTC para iniciar la conexión de media. Luego recibes los webhooks de estado (RINGING, ACCEPTED, REJECTED). El webhook de estado ACCEPTED llega después de que la llamada se establece; Cloud API lo envía para auditoría de eventos.
  4. Terminar la llamada: tu negocio o el usuario pueden colgar. Cuando termina, recibes el webhook Terminate.

Para realizar una llamada a un usuario, la empresa debe obtener primero el permiso del usuario. Cuando un usuario otorga permisos de llamada, pueden ser temporales o permanentes. Desde el 3 de noviembre de 2025, los permisos permanentes están disponibles: el usuario puede otorgar a un negocio un permiso continuo para llamar. El usuario puede revisar y cambiar el permiso en cualquier momento desde el perfil del negocio.

La empresa no tiene control sobre este permiso; solo el usuario puede otorgarlo o revocarlo, en cualquier momento. WhatsApp almacena los datos del permiso permanente hasta que el usuario lo revoca.

Una empresa puede obtener permiso de las siguientes maneras:

  1. Enviar una solicitud de permiso de llamada al usuario — mensaje de formato libre o plantilla; el usuario elige entre temporal o permanente.
  2. Permiso de devolución de llamada — el usuario otorga automáticamente un permiso temporal al llamar al negocio. Debes habilitar callback_permission_status en el número.
  3. Permiso vía perfil del negocio — el usuario otorga permiso a través del perfil del negocio.

Nota: las funciones de permiso de llamada están disponibles solo en las regiones donde las llamadas iniciadas por el negocio están disponibles.

Cuando el consumidor lo otorga, un permiso de llamada permite llamar al usuario sujeto a las siguientes restricciones (por par empresa + consumidor):

Diagrama: llamada de consumidor a empresa

ConceptoDescripciónLímites
Duración del permisoPeríodo en el que la empresa puede llamar desde la aprobación.Temporal: 7 días calendario (168 horas) desde la aprobación. Permanente: sin límite (mismo límite de llamadas conectadas).
Límites de llamadasLlamadas conectadas que la empresa puede hacer al usuario. Las fallidas no cuentan.100 llamadas conectadas por usuario cada 24 horas. Aplican al número de teléfono del negocio.

Solicitud de permiso al usuario

La solicitud de permiso se envía como mensaje interactivo de formato libre o como mensaje de plantilla. El consumidor puede aprobar, rechazar o no responder; también puede cambiar su respuesta antes de que caduque.

La solicitud caduca cuando ocurre cualquiera de estos casos:

  • El consumidor interactúa con una nueva solicitud de permiso subsiguiente.
  • 7 días después de que el consumidor aceptó o rechazó el permiso.
  • 7 días después de la entrega si el consumidor no responde.

Límites de envío:

  • Máximo 1 solicitud de permiso en 24 horas y 2 solicitudes en 7 días por par. El límite se restablece con una llamada conectada entre la empresa y el consumidor.
  • 2 llamadas consecutivas sin respuesta generan un mensaje del sistema para reconsiderar el permiso aprobado.
  • 4 llamadas consecutivas sin respuesta revocan automáticamente el permiso aprobado.

Formas de envío:

  1. Mensaje de formato libre: en respuesta a un mensaje del usuario, sujeto a la ventana de atención al cliente. El cuerpo de texto es opcional; encabezado y pie no son compatibles.
  2. Mensaje de plantilla: permite iniciar una conversación con una solicitud de llamada. El cuerpo es obligatorio; admite encabezado y pie.

Solicitud de permiso de llamada

Diagrama: llamada de empresa a consumidor

API: Enviar solicitud de permiso de formato libre

Endpoint: POST /{v}/{did}/messages

Request:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "<phone number> or <wa_id>",
  "recipient": "US.13491208655302741918",
  "type": "interactive",
  "interactive": {
    "type": "call_permission_request",
    "action": {
      "name": "call_permission_request"
    },
    "body": {
      "text": "We would like to call you to help support your query on Order No: ON-12345."
    }
  }
}

Response (200):

{
  "messaging_product": "whatsapp",
  "contacts": [
    {
      "input": "+1-408-555-1234",
      "wa_id": "14085551234",
      "user_id": "<BSUID>",
      "parent_user_id": "<PARENT_BSUID>"
    }
  ],
  "messages": [
    {
      "id": "wamid.gBGGFlaCmZ9plHrf2Mh-o"
    }
  ]
}

Notas:

  • Solo los campos type y action.name son obligatorios. action.name debe ser call_permission_request.
  • to es requerido (salvo recipient); recipient (BSUID o parent BSUID) puede usarse en su lugar o además. Si se envían ambos, to tiene prioridad.
  • body es opcional y da contexto al usuario.
  • La empresa no puede editar el contenido del mensaje interactivo de solicitud de permiso de llamada; solo el body.
  • Requiere una ventana de atención al cliente abierta con la cuenta de usuario.
  • Enviar a usuarios en versiones antiguas genera un webhook de error con código 131026.

API: Crear plantilla con solicitud de permiso

Endpoint: POST /message_templates/{v}/{did}

Request:

{
  "name": "sample_cpr_template",
  "language": "en",
  "category": "UTILITY",
  "components": [
    {
      "type": "HEADER",
      "text": "Support of Order No: {{1}}",
      "example": {
        "body_text": [["ON-12345"]]
      }
    },
    {
      "type": "BODY",
      "text": "We would like to call you to help support your query on Order No: {{1}} for the item {{2}}.",
      "example": {
        "body_text": [["ON-12345", "Avocados"]]
      }
    },
    {
      "type": "FOOTER",
      "text": "Talk to you soon!"
    },
    {
      "type": "call_permission_request"
    }
  ]
}

Response (200):

{
  "id": "<ID>",
  "status": "<STATUS>",
  "category": "<CATEGORY>"
}

Notas:

  • El componente body es obligatorio y solo admite texto.
  • Encabezado y pie son opcionales.
  • Categorías soportadas: Marketing y Utilidad.
  • El tipo call_permission_request identifica la plantilla.
  • Los medios no son compatibles con esta plantilla.

API: Enviar plantilla de solicitud de permiso

Endpoint: POST /{v}/{did}/messages

Request:

{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "{user number}",
  "type": "template",
  "template": {
    "name": "sample_cpr_template",
    "language": {
      "policy": "deterministic",
      "code": "en_US"
    },
    "components": [
      {
        "type": "header",
        "parameters": [
          {
            "type": "text",
            "text": "ON-12345"
          }
        ]
      },
      {
        "type": "body",
        "parameters": [
          {
            "type": "text",
            "text": "ON-12345"
          },
          {
            "type": "text",
            "text": "Avocados"
          }
        ]
      }
    ]
  }
}

Response (200):

{
  "messaging_product": "whatsapp",
  "contacts": [
    {
      "input": "+1-408-555-1234",
      "wa_id": "+1-408-555-1234"
    }
  ],
  "messages": [
    {
      "id": "wamid.gBGGFlaCmZ9plHrf2Mh-o"
    }
  ]
}

API: Obtener el estado del permiso de llamada

Obtiene el estado del permiso de llamada para un número de teléfono de negocio con un único usuario de WhatsApp. Puedes identificar al usuario por su número (user_wa_id) o por su BSUID (recipient).

Endpoint: GET /calls/{v}/{did}/call_permissions?user_wa_id={user_whatsapp_id}

O usando un BSUID:

Endpoint: GET /calls/{v}/{did}/call_permissions?recipient={BSUID}

Response (200):

{
  "messaging_product": "whatsapp",
  "permission": {
    "status": "temporary",
    "expiration_time": 1745343479
  },
  "actions": [
    {
      "action_name": "send_call_permission_request",
      "can_perform_action": true,
      "limits": [
        {
          "time_period": "PT24H",
          "max_allowed": 1,
          "current_usage": 0
        },
        {
          "time_period": "P7D",
          "max_allowed": 2,
          "current_usage": 1
        }
      ]
    },
    {
      "action_name": "start_call",
      "can_perform_action": false,
      "limits": [
        {
          "time_period": "PT24H",
          "max_allowed": 5,
          "current_usage": 5,
          "limit_expiration_time": 1745622600
        }
      ]
    }
  ]
}

Campos de la respuesta:

CampoDescripción
permission.statusno_permission, temporary o permanent.
permission.expiration_timeMarca de tiempo Unix (segundos) de expiración del permiso. Ausente para permisos permanentes.
actions[].action_namesend_call_permission_request o start_call.
actions[].can_perform_actionIndica si la acción se puede realizar ahora, considerando todos los límites.
actions[].limits[]Restricciones por período: time_period (ISO 8601, ej. PT24H, P7D), max_allowed, current_usage y limit_expiration_time (opcional).

Errores:

CódigoCaso
400Formato de número de teléfono del consumidor no válido
401No se encontró ningún permiso aprobado
429Límite de velocidad alcanzado (máximo 100 solicitudes en 1 segundo)

Webhooks de permiso de llamada

Aprobación temporal

Cuando el consumidor aprueba un permiso temporal, la sección interactive del webhook de mensajes contiene call_permission_reply.

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "{phone-number-id}",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "{phone-number}",
              "phone_number_id": "{phone-number-id}"
            },
            "contacts": [
              {
                "profile": { "name": "NAME" },
                "wa_id": "{phone-number}"
              }
            ],
            "messages": [
              {
                "from": "{phone-number}",
                "id": "wamid.sH0kFlaCGg0xcvZbgmg90lHrg2dL",
                "timestamp": "{TIMESTAMP}",
                "context": {
                  "from": "{phone-number}",
                  "id": "wamid.gBGGFlaCmZ9plHrf2Mh-o"
                },
                "interactive": {
                  "type": "call_permission_reply",
                  "call_permission_reply": {
                    "response": "accept",
                    "is_permanent": false,
                    "expiration_timestamp": "{timestamp}",
                    "response_source": "user_action"
                  }
                }
              }
            ]
          },
          "field": "messages"
        }
      ]
    }
  ]
}

Aprobación permanente

Igual que la aprobación temporal, con is_permanent: true y sin expiration_timestamp.

Rechazo

Igual que la aprobación, con response: "reject". response_source puede ser user_action (el usuario rechazó) o automatic (rechazo automático por límites de llamadas no contestadas).

Permiso desde el flujo de callback

Cuando el permiso se otorga tras una llamada iniciada por el consumidor perdida, el context.id contiene el ID de llamada de la llamada perdida.

Campos de call_permission_reply:

CampoDescripción
responseaccept o reject.
is_permanentIndica si el permiso es permanente.
expiration_timestampMarca de tiempo Unix de expiración si el consumidor aprobó.
response_sourceuser_action (el usuario aprobó o rechazó) o automatic (aprobación automática tras una llamada iniciada por el usuario, o rechazo automático por límites).

Iniciar una nueva llamada

Inicia una llamada a un usuario de WhatsApp. Hay un límite de 10,000 llamadas nuevas por 24 horas por número de teléfono de negocio.

Endpoint: POST /calls/{v}/{did}/signaling

Request:

{
  "messaging_product": "whatsapp",
  "to": "14085551234",
  "recipient": "US.13491208655302741918",
  "action": "connect",
  "session": {
    "sdp_type": "offer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "biz_opaque_callback_data": "0fS5cePMok"
}

Response (200):

{
  "messaging_product": "whatsapp",
  "calls": [
    {
      "id": "wacid.ABGGFjFVU2AfAgo6V"
    }
  ]
}

Parámetros del body:

CampoRequeridoDescripción
toRequerido (salvo recipient)El número del usuario al que se llama. Puede identificarse por número (to), BSUID (recipient) o ambos. Si envías ambos, to tiene prioridad.
recipientNoBSUID o parent BSUID del usuario de WhatsApp. Úsalo en lugar de, o además de, to.
actionconnect para iniciar una nueva llamada.
sessionContiene sdp_type (offer) y sdp. El SDP debe cumplir con RFC 8866.
biz_opaque_callback_dataNoCadena arbitraria para tracking. Máximo 512 caracteres. Incluida en los webhooks posteriores.

Errores:

CódigoCaso
400Errores de validación del formato de solicitud (SDP, ICE, etc.)
401Errores de permisos o autorización
138006El consumidor no tiene permiso para llamadas a este número

Webhooks de estado de llamada

Se envía en determinados eventos de una llamada iniciada por la empresa: ringing (cuando la llamada comienza a sonar), accepted (el consumidor acepta) y rejected (el consumidor rechaza).

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "whatsapp-business-account-id",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "16315553601",
              "phone_number_id": "phone-number-id"
            },
            "statuses": [
              {
                "id": "wacid.ABGGFjFVU2AfAgo6V",
                "timestamp": "1671644824",
                "type": "call",
                "status": "RINGING",
                "recipient_id": "16315553602",
                "biz_opaque_callback_data": "random data"
              }
            ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}

Campos de statuses:

CampoDescripción
idID de la llamada para la que es este estado.
typecall para webhooks de llamadas.
recipient_idNúmero de teléfono del consumidor de WhatsApp al que se dirige la llamada.
timestampMarca de tiempo del evento.
statusRINGING, ACCEPTED o REJECTED.
biz_opaque_callback_dataSolo disponible si se proporcionó en la solicitud de llamada.

Grabación de llamadas

La API de Calling puede grabar el audio de las llamadas iniciadas por el negocio (BIC) y por el usuario (UIC). Cuando optas por grabar una llamada, ambos participantes escuchan un anuncio corto obligatorio por ley antes de que comience la grabación. Después de que termina la llamada, recibes un webhook con un media ID para descargar la grabación.

La grabación es opt-in por llamada: decides al iniciar o aceptar cada llamada si se graba. Es independiente de la transcripción de llamadas: puedes habilitar una, ambas o ninguna. Cada una se configura y cobra por separado, tiene su propio objeto de request y entrega su resultado en su propio evento de webhook.

Habilitar grabación en una llamada iniciada por el negocio

Agrega un objeto recording al body de tu solicitud de llamada iniciada por el negocio:

Endpoint: POST /calls/{v}/{did}/signaling

{
  "messaging_product": "whatsapp",
  "to": "14085551234",
  "recipient": "US.13491208655302741918",
  "action": "connect",
  "session": {
    "sdp_type": "offer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "recording": {
    "status": "ENABLED",
    "purpose": "quality assurance",
    "announcement_language": "en_US"
  }
}

Habilitar grabación en una llamada iniciada por el usuario

Agrega el mismo objeto recording al aceptar una llamada entrante:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V",
  "action": "accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "recording": {
    "status": "ENABLED",
    "purpose": "quality assurance",
    "announcement_language": "en_US"
  }
}

Para aceptar una llamada entrante sin grabarla, omite el campo recording o envíalo con "status": "DISABLED".

Anuncios y consentimiento

Antes de grabar cualquier audio, la API mezcla un anuncio hablado en los streams de audio del negocio y del usuario. El anuncio se genera a partir del string purpose y el announcement_language que proporciones, por ejemplo:

“El audio de esta llamada se grabará con el siguiente propósito: <tu propósito>.”

La grabación comienza solo después de que el anuncio termina. Un participante que no consienta puede rechazar terminando la llamada antes o durante el anuncio. El campo purpose es obligatorio cuando status es ENABLED; las llamadas con grabación habilitada pero sin propósito se rechazan con un error de request.

Referencia del objeto recording

CampoTipoRequeridoDescripción
statusStringENABLED para grabar la llamada, DISABLED para optar explícitamente por no grabar.
purposeStringSí, cuando status es ENABLEDEl propósito de la grabación, hablado a ambos participantes como parte del anuncio. Máximo 250 caracteres. Provéelo en el idioma de announcement_language.
announcement_languageStringSí, cuando status es ENABLEDCódigo de locale para el idioma del anuncio, por ejemplo en_US o es.

Idiomas de anuncio soportados

Idiomaannouncement_language
Inglésen (también en_US, en_AU, en_CA, en_GB, en_IN, en_NZ)
Neerlandésnl
Francésfr
Alemánde
Hindihi
Italianoit
Canaréskn
Portugués (Brasil)pt
Español (Latinoamérica)es
Español (España)es_ES
Telugute
Vietnamitavi

Grabación con transcripción

La grabación y la transcripción son totalmente independientes. Los objetos recording y transcription son campos de request separados; eliges cada uno por llamada:

  • Solo recording → audio, sin transcripción.
  • Solo transcription → transcripción, sin audio.
  • Ambos → audio y transcripción.
  • Ninguno (o ambos DISABLED) → ninguno.

Cuando habilitas ambos en la misma llamada, los participantes escuchan un anuncio combinado:

“El audio de esta llamada se grabará y transcribirá con el siguiente propósito: <tu propósito>.”

Cuando ambos objetos están presentes, se usan announcement_language y purpose del objeto recording para el anuncio combinado; los valores correspondientes del objeto transcription se ignoran. Aun así, recibes un webhook separado por cada feature habilitada.

Webhook de grabación disponible

Después de que la llamada termina y el post-procesamiento finaliza (típicamente en menos de un minuto), la API envía un evento call_recording_available bajo el campo de webhook calls:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<WABA_ID>",
      "changes": [
        {
          "field": "calls",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "phone_number_id": "<BUSINESS_PHONE_NUMBER_ID>",
              "display_phone_number": "<BUSINESS_DISPLAY_PHONE_NUMBER>"
            },
            "calls": [
              {
                "id": "wacid.HBgLMTQxMjYxMzYyNTMVAgASGCBGO...",
                "from": "<USER_PHONE_NUMBER>",
                "from_user_id": "<BSUID>",
                "from_parent_user_id": "<PARENT_BSUID>",
                "timestamp": "1728932177",
                "event": "call_recording_available",
                "call_recording": {
                  "type": "audio",
                  "audio": {
                    "id": "1002764438271669",
                    "sha256": "Y9vvGyeo3n76ptkXu3CwDBsnzbRFqpjHskQdMGSVqas=",
                    "mime_type": "audio/ogg; codecs=opus",
                    "url": "https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=133..."
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

Campos de call_recording:

CampoTipoDescripción
typeStringTipo de media de la grabación. Actualmente siempre audio.
audio.idStringID del asset de media. Úsalo con la Media API para recuperar la URL de descarga.
audio.sha256StringHash SHA-256 base64 de la grabación. Úsalo para verificar la integridad del archivo descargado.
audio.mime_typeStringTipo MIME de la grabación, por ejemplo audio/ogg; codecs=opus.
audio.urlStringURL de descarga de corta duración. Emite un GET autenticado con tu access token para descargar el asset.

Descargar la grabación

Las grabaciones usan el mismo flujo de descarga que los mensajes de media:

  1. La url del webhook es válida por 5 minutos. Emite un GET autenticado con tu access token para descargar el archivo.
  2. Si la URL expiró, usa la Media API para recuperar una URL fresca con el audio.id.

Retención

Las grabaciones permanecen disponibles para descarga durante 7 días después de que se entrega el webhook call_recording_available. Después, el media ID expira y el archivo subyacente se elimina. Descarga y persiste la grabación en tu propio almacenamiento dentro de la ventana de retención si necesitas mantenerla a largo plazo.

Errores

EscenarioDescripción
purpose faltanterecording.status es ENABLED pero purpose se omitió o está vacío.
purpose demasiado largopurpose excede 250 caracteres.
announcement_language inválidoannouncement_language no es un código de locale soportado.
status inválidostatus no es ENABLED ni DISABLED.

Transcripción de llamadas

La API de Calling puede transcribir el audio de las llamadas iniciadas por el negocio (BIC) y por el usuario (UIC). Cuando optas por transcribir una llamada, ambos participantes escuchan un anuncio corto obligatorio por ley antes de que comience la transcripción. Después de que termina la llamada, recibes un webhook con un media ID para descargar la transcripción como un documento JSON.

La transcripción es opt-in por llamada: decides al iniciar o aceptar cada llamada si se transcribe. Es independiente de la grabación de llamadas: puedes habilitar una, ambas o ninguna. Cada una se configura y cobra por separado, tiene su propio objeto de request y entrega su resultado en su propio evento de webhook.

Habilitar transcripción en una llamada iniciada por el negocio

Agrega un objeto transcription al body de tu solicitud de llamada iniciada por el negocio:

Endpoint: POST /calls/{v}/{did}/signaling

{
  "messaging_product": "whatsapp",
  "to": "14085551234",
  "recipient": "US.13491208655302741918",
  "action": "connect",
  "session": {
    "sdp_type": "offer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "transcription": {
    "status": "ENABLED",
    "purpose": "quality assurance",
    "announcement_language": "en_US"
  }
}

Habilitar transcripción en una llamada iniciada por el usuario

Agrega el mismo objeto transcription al aceptar una llamada entrante:

{
  "messaging_product": "whatsapp",
  "call_id": "wacid.ABGGFjFVU2AfAgo6V",
  "action": "accept",
  "session": {
    "sdp_type": "answer",
    "sdp": "<<RFC 8866 SDP>>"
  },
  "transcription": {
    "status": "ENABLED",
    "purpose": "quality assurance",
    "announcement_language": "en_US"
  }
}

Para aceptar una llamada entrante sin transcribirla, omite el campo transcription o envíalo con "status": "DISABLED".

Anuncios y consentimiento

Antes de transcribir cualquier audio, la API mezcla un anuncio hablado en los streams de audio del negocio y del usuario:

“El audio de esta llamada se transcribirá con el siguiente propósito: <tu propósito>.”

La transcripción comienza solo después de que el anuncio termina. Un participante que no consienta puede rechazar terminando la llamada antes o durante el anuncio. El campo purpose es obligatorio cuando status es ENABLED; las llamadas con transcripción habilitada pero sin propósito se rechazan con un error de request.

Referencia del objeto transcription

CampoTipoRequeridoDescripción
statusStringENABLED para transcribir la llamada, DISABLED para optar explícitamente por no transcribir.
purposeStringSí, cuando status es ENABLEDEl propósito de la transcripción, hablado a ambos participantes como parte del anuncio. Máximo 250 caracteres. Provéelo en el idioma de announcement_language.
announcement_languageStringSí, cuando status es ENABLEDCódigo de locale para el idioma del anuncio, por ejemplo en_US o es.

Idiomas de anuncio soportados

Idiomaannouncement_language
Inglésen (también en_US, en_AU, en_CA, en_GB, en_IN, en_NZ)
Francésfr
Alemánde
Hindihi
Italianoit
Canaréskn
Portugués (Brasil)pt
Españoles
Telugute
Vietnamitavi

Nota: announcement_language también acepta nl y es_ES. Son válidos, pero hasta que haya un anuncio de transcripción localizado, reproducen el anuncio en inglés.

Transcripción con grabación

La transcripción y la grabación son totalmente independientes. Cuando habilitas ambas en la misma llamada, los participantes escuchan un anuncio combinado:

“El audio de esta llamada se grabará y transcribirá con el siguiente propósito: <tu propósito>.”

Cuando ambos objetos están presentes, se usan announcement_language y purpose del objeto recording para el anuncio combinado; los valores correspondientes del objeto transcription se ignoran. Aun así, recibes un webhook separado por cada feature habilitada.

Webhook de transcripción disponible

Después de que la llamada termina y el post-procesamiento finaliza (típicamente en menos de un minuto), la API envía un evento call_transcription_available bajo el campo de webhook calls:

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<WABA_ID>",
      "changes": [
        {
          "field": "calls",
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "phone_number_id": "<BUSINESS_PHONE_NUMBER_ID>",
              "display_phone_number": "<BUSINESS_DISPLAY_PHONE_NUMBER>"
            },
            "calls": [
              {
                "id": "wacid.HBgLMTQxMjYxMzYyNTMVAgASGCBGO...",
                "from": "<USER_PHONE_NUMBER>",
                "from_user_id": "<BSUID>",
                "from_parent_user_id": "<PARENT_BSUID>",
                "timestamp": "1728932177",
                "event": "call_transcription_available",
                "call_transcript": {
                  "document": {
                    "id": "1002764438271669",
                    "sha256": "Y9vvGyeo3n76ptkXu3CwDBsnzbRFqpjHskQdMGSVqas=",
                    "mime_type": "application/json",
                    "url": "https://lookaside.fbsbx.com/whatsapp_business/attachments/?mid=133..."
                  }
                }
              }
            ]
          }
        }
      ]
    }
  ]
}

Campos de call_transcript:

CampoTipoDescripción
document.idStringID del asset de media. Úsalo con la Media API para recuperar la URL de descarga.
document.sha256StringHash SHA-256 base64 del documento de transcripción. Úsalo para verificar la integridad del archivo descargado.
document.mime_typeStringTipo MIME del documento. Actualmente siempre application/json.
document.urlStringURL de descarga de corta duración. Emite un GET autenticado con tu access token para descargar el asset.

Idioma de la transcripción

No especificas un idioma de transcripción en el request. La API detecta automáticamente el idioma hablado, lo transcribe y lo reporta en el campo transcript.language del documento (código ISO 639, por ejemplo en). Este idioma es independiente del announcement_language.

El conjunto de idiomas detectables evoluciona constantemente e incluye (entre otros): inglés, español, portugués, francés, alemán, italiano, hindi, árabe, chino, japonés, coreano, ruso, turco, vietnamita y más de 50 idiomas. Si la llamada se habla en un idioma no soportado, igual recibes el webhook call_transcription_available, pero la transcripción puede estar vacía.

Formato del documento de transcripción

El documento descargado es un JSON con dos objetos de nivel superior: metadata (información del audio procesado) y transcript (el contenido transcrito).

{
  "metadata": {
    "processed_at": "2026-06-18T20:16:47Z",
    "audio": {
      "duration": 21.76,
      "sample_rate": 16000,
      "channels": 2,
      "audio_format": "stereo"
    }
  },
  "transcript": {
    "text": "[Business] Hello, how about you? [Customer] Hey, I'm good. How are you?",
    "language": "en",
    "duration": 21.76,
    "confidence": 0.83,
    "segments": [
      {
        "id": 1,
        "speaker": "Business",
        "channel": 0,
        "start": 1.16,
        "end": 2.44,
        "text": "Hello, how about you?",
        "confidence": 0.85,
        "words": [
          {
            "word": "Hello,",
            "start": 1.16,
            "end": 1.64,
            "confidence": 0.89,
            "lang": "en"
          }
        ]
      }
    ]
  }
}

Campos de metadata:

CampoTipoDescripción
processed_atStringMarca de tiempo ISO 8601 UTC del post-procesamiento.
audio.durationNúmeroDuración del audio procesado, en segundos.
audio.sample_rateEnteroFrecuencia de muestreo del audio, en Hz.
audio.channelsEnteroNúmero de canales de audio. Una llamada a dos partes tiene dos canales.
audio.audio_formatStringFormato de la mezcla, por ejemplo stereo.

Campos de transcript:

CampoTipoDescripción
textStringLa conversación completa como string único, con cada segmento prefijado con su etiqueta de hablante, por ejemplo [Business] o [Customer].
languageStringIdioma detectado como código ISO 639.
durationNúmeroDuración total del audio transcrito, en segundos.
confidenceNúmeroPuntaje de confianza general de 0 a 1.
segmentsArrayLista ordenada de segmentos hablados.

Campos de segments:

Cada segmento representa un tramo continuo de habla de un hablante.

CampoTipoDescripción
idEnteroIdentificador secuencial del segmento.
speakerStringBusiness o Customer.
channelEnteroCanal de audio del segmento. El canal 0 es el negocio; el canal 1 es el usuario de WhatsApp.
start / endNúmeroTiempo de inicio y fin del segmento, en segundos desde el inicio del audio.
textStringTexto transcrito del segmento.
confidenceNúmeroConfianza de 0 a 1.
wordsArrayDesglose palabra a palabra: word, start, end, confidence y lang (código ISO 639).

Descargar la transcripción

Las transcripciones usan el mismo flujo de descarga que los mensajes de media:

  1. La url del webhook es válida por 5 minutos. Emite un GET autenticado con tu access token para descargar el archivo.
  2. Si la URL expiró, usa la Media API para recuperar una URL fresca con el document.id.

Retención

Las transcripciones permanecen disponibles para descarga durante 7 días después de que se entrega el webhook call_transcription_available. Después, el media ID expira y el archivo subyacente se elimina. Descarga y persiste la transcripción en tu propio almacenamiento dentro de la ventana de retención si necesitas mantenerla a largo plazo.

Errores

EscenarioDescripción
purpose faltantetranscription.status es ENABLED pero purpose se omitió o está vacío.
purpose demasiado largopurpose excede 250 caracteres.
announcement_language inválidoannouncement_language no es un código de locale soportado.
status inválidostatus no es ENABLED ni DISABLED.

Mejores prácticas de integración

Problema y solución de recorte de audio

Al conectar el segmento de medios del consumidor de WhatsApp (WebRTC) con otro segmento de medios (por ejemplo SIP), puede producirse recorte de audio: el consumidor pierde aproximadamente un segundo del mensaje del negocio (por ejemplo, un IVR que reproduce 1-2-3 puede escucharse solo desde el 2).

Causa raíz: cuando un servidor de medios conecta dos segmentos, debe asegurarse de que ambos estén aproximadamente listos al mismo tiempo. Si el segmento SIP envía medios antes de que el segmento WebRTC esté listo, los paquetes se descartan y se produce el recorte.

Diagrama de secuencia: problema de recorte de audio

Solución sugerida: un agente WebRTC no debe transmitir medios hasta que el proceso ICE esté casi completo. Esto se logra con una aceptación optimista: invoca la pre-aceptación incluso antes de enviar el INVITE SIP. Según RFC, un UAC debe estar listo para recibir medios justo después de enviar el INVITE.

Diagrama de secuencia: solución al recorte de audio

Puntos clave:

  • Al recibir el webhook de conexión, inicializa el agente WebRTC, prepara la respuesta SDP y llama a la pre-aceptación con esa respuesta SDP.
  • Espera a que el proceso ICE complete la creación de listas válidas antes de enviar medios.
  • Si el UA SIP rechaza la llamada en lugar de enviar un 200 OK, llama a la API de terminación.
  • Si la conexión del consumidor está lista antes que la SIP, el consumidor puede escuchar unos milisegundos de silencio, lo cual es mejor que perder el audio inicial.

Otras alternativas: forzar al UA SIP a no reproducir audio hasta recibir el ACK de WebRTC, hasta detectar el estado conectado, almacenar en búfer los paquetes SIP y enviarlos al establecer la conexión, o insertar silencio en el IVR antes del audio real.

Patrones de integración

Una app vs. múltiples apps

Para integrar la API de Calling necesitas llamar a endpoints de la Graph API y procesar webhooks de Meta, lo que requiere una app. Casi siempre ya tienes una app usada para mensajería, y puedes reutilizarla para llamadas.

En esta configuración, la URI del webhook es la misma para webhooks de mensajes y de llamadas, pero el payload del webhook permite distinguir ambas categorías. Puedes reenviar los webhooks específicos de llamadas a un componente relacionado desde tu lógica de webhook principal.

Reutilizar la misma app ofrece:

  • Menor overhead operativo (revisión de app, mantenimiento continuo).
  • Huella simplificada en Meta.
  • Igualdad entre la app usada para Embedded Signup y la usada para invocar Graph APIs y recibir webhooks.
  • Sin impacto en la funcionalidad existente; solo debes asegurar que tu servidor de webhook maneje correctamente los webhooks de llamadas.

Usar apps separadas también está soportado.

Integración con un proveedor de calling de terceros

En este escenario, usas un proveedor (vendor) de calling de terceros internamente, y ese proveedor no es visible para Meta. El patrón es similar a cualquier otro servicio SaaS. Esta arquitectura puede extenderse opcionalmente para integrarse con infraestructura SIP de tu lado.

Advertencia: nuestros términos prohíben el uso de PSTN en cualquier tramo de la llamada de WhatsApp en el flujo general. Aunque conectes la llamada de WA al mundo SIP, debes asegurarte de que siga siendo exclusivamente VoIP y nunca toque la PSTN. Un troncal SIP por sí mismo no está prohibido, porque técnicamente puede usarse sin PSTN.

Guías para la integración de la ruta de media

El stack VoIP de WhatsApp Business Calling está diseñado para ser compatible con WebRTC, pero Meta restringe las funcionalidades soportadas.

Requisitos obligatorios (si no se cumplen, la llamada falla durante la señalización o la decodificación de paquetes):

  • Usa solo los códecs soportados.
  • Para Opus, usa un clock rate de media de 48 kHz.
  • Para Opus, usa un ptime de 20 ms.
  • El audio debe usar un único SSRC. El servidor relay de Meta sobrescribe el SSRC de todos los paquetes de audio del negocio a un SSRC fijo antes de que lleguen al cliente de WA. Los clientes de WA manejan solo una fuente de audio de sus pares. Usar múltiples SSRC causa comportamiento indefinido: corrupción severa de media, glitches de audio y probablemente falla total.
  • Configura el clock rate de DTMF a 8 kHz.

Recomendaciones (para alta calidad y confiabilidad):

  • Proceso ICE: el stack de Meta es ICE-LITE; se recomienda que el stack del Solution Partner sea ICE-FULL (RFC 5245 §2.7). El stack del partner debe iniciar el proceso ICE enviando checks STUN, asumir el rol ICE CONTROLLING (Meta asume CONTROLLED), usar nominación regular (no agresiva) (RFC 5245 §8.1.1.2), esperar a que el ICE complete antes de nominar el candidato y comenzar DTLS, y no cambiar de candidato a mitad de la llamada.
  • DTLS: usa claves ECDH para los certificados DTLS para evitar fragmentación de paquetes. El Solution Partner debe actuar como cliente DTLS (RFC 6347 §4.2).
  • Media: WhatsApp puede no enviar siempre el primer paquete RTP. La salida de media de tu servidor no debe esperar a la entrada de media de WhatsApp; si lo hace, existe el riesgo de deadlock donde cada lado espera al otro.
  • Recorte de audio: ver la sección de recorte de audio más arriba.

Ejemplos de integración

Meta documenta ejemplos de integración con plataformas VoIP comunes. Estas guías son solo informativas, sin soporte ni garantías de Meta ni de ningún vendor; hay muchas formas de integrar y las guías explican una sola, con fines ilustrativos.

Asterisk usando SIP

Integración de la API de Calling usando señalización SIP con Asterisk, un PBX open-source.

  • Llamadas iniciadas por el usuario: el usuario de WhatsApp marca el número del negocio; la llamada llega a Asterisk y se enruta por un IVR que pide una extensión registrada en el mismo servidor; la llamada se conecta a esa extensión.
  • Llamadas iniciadas por el negocio: el agente se registra en Asterisk con credenciales SIP; marca la extensión b2c-sip, el IVR pide el número de WhatsApp a llamar, y la llamada se conecta al usuario.
  • El tramo WA → Asterisk usa SDES para intercambio de claves de media y Opus como códec. El tramo Asterisk → SIP UA usa SDES y Opus o G.711.

Troubleshooting clave — no recibir ACK de Meta o el audio del negocio se corta a los ~30s:

Si Meta envía un SIP INVITE, tu servidor responde 200 OK, pero nunca recibes el ACK y el servidor SIP termina el diálogo por timeout de ACK (típicamente 32s), la causa más probable son los encabezados Record-Route incorrectos en tu 200 OK. La respuesta 200 OK no debe modificar los encabezados Record-Route incluidos en el INVITE original de Meta (puedes agregar nuevos, pero no modificar los presentes). La solución es rewrite_contact=no en la configuración del endpoint de WhatsApp en pjsip.conf, y asegurar que tu 200 OK tenga como últimos 2 encabezados:

Record-Route: <sip:wa.meta.vc;transport=tls;lr>
Record-Route: <sip:onevc-sip-proxy.fbinfra.net:8191;transport=tls;lr>

FreeSWITCH usando SIP

Integración con FreeSWITCH usando señalización SIP. Misma estructura de flujo que Asterisk (IVR para extensiones y para llamadas B2C vía b2c-sip). El tramo WA → FreeSWITCH usa SDES con Opus; el tramo FreeSWITCH → SIP UA usa SDES con Opus o G.711.

Puntos clave: FreeSWITCH escucha en 5081 para TLS; el dialplan wa-biz-api-dialplan.xml verifica que la solicitud venga de wa.meta.vc y usa check_acl con la lista de IPs permitidas de Meta; se agrega un stream de silencio de 1 segundo para establecer la ruta de media y evitar recorte de audio.

FreeSWITCH usando Graph API con Janus

Integración usando la señalización de Cloud API (Graph APIs + Webhooks) con FreeSWITCH y Janus, un servidor WebRTC de propósito general.

  • Un módulo de integración se sitúa entre WA y Janus y traduce los mensajes de Cloud API Signaling a mensajes del plugin SIP de Janus y viceversa.
  • Janus convierte la media de WA (WebRTC, intercambio de claves DTLS) a la media negociada con FreeSWITCH (SDES).
  • Llamadas iniciadas por el negocio: el SIP INVITE llega a Janus en la extensión 1000, se convierte a un request de Graph API con el SDP del INVITE como offer; cuando el usuario acepta, se acepta el SIP INVITE pasando el SDP answer del webhook connect.
  • Llamadas iniciadas por el usuario: el webhook recibe la llamada entrante con el SDP offer; el plugin SIP de Janus envía un INVITE a FreeSWITCH (destino c2b-sip); al recibir el 200 OK, se envía un request accept a Meta con el SDP del answer.

Asterisk usando Graph API con RtpEngine

Integración usando la señalización de Cloud API con Asterisk y RtpEngine, un proxy para relaying y control de flujos RTP. RtpEngine actúa como proxy de media entre WA (WebRTC, DTLS) y Asterisk (SDES).

El módulo de integración traduce Cloud API Signaling a SIP para Asterisk, usa el protocolo ng de RtpEngine para el bridging de media, y conecta vía extensión 1000 reservada. Para iniciar una llamada: Asterisk envía un SIP INVITE a la extensión 1000 con un header personalizado con el número de WA; el SDP del INVITE se envía a RtpEngine, que devuelve un nuevo SDP; ese SDP se usa en el request de Graph API para iniciar la llamada.

Asterisk con WebRTC integrado usando Graph API

Similar a Asterisk + RtpEngine, pero usando el soporte WebRTC integrado de Asterisk (no requiere RtpEngine). En la configuración de la extensión 1000, webrtc=yes habilita de forma abreviada: use_avpf=yes, media_encryption=dtls, dtls_verify=fingerprint, dtls_setup=actpass, ice_support=yes, media_use_received_transport=yes, rtcp_mux=yes.

Modelo de precios

Advertencia: todas las llamadas iniciadas por el usuario son gratuitas.

Información general

Las empresas pagan por las llamadas en función de:

  • La duración de la llamada (calculada en pulsos de seis segundos).
  • El código de país del número de teléfono al que se llama.
  • El nivel de volumen (según los minutos llamados dentro del mes calendario), usando el mismo devengo por niveles (tiering accrual) que la mensajería.

Nota: nuestros sistemas cuentan los pulsos fraccionarios como un pulso completo. Por ejemplo, una llamada de 56 segundos (9.33 pulsos) se contaría como 10 pulsos.

Para las llamadas que cruzan niveles de precios (por ejemplo, del nivel 0–50,000 al nivel 50,001–250,000), toda la llamada se cobra a la tarifa más baja (es decir, la del nivel de mayor volumen).

Se requiere un método de pago válido para realizar llamadas.

Nota: los mensajes de solicitud de permiso de llamada están sujetos a la tarificación por mensaje.

Tarjetas de tarifas y niveles de volumen

Estas tarjetas de tarifas representan las tarifas y niveles de volumen actuales de la WhatsApp Business Calling API, vigentes desde el 1 de abril de 2026, según la zona horaria de la cuenta de WhatsApp Business.

MonedaTarifas
USDTarifas USD
AEDTarifas AED
ARSTarifas ARS
AUDTarifas AUD
CLPTarifas CLP
COPTarifas COP
EURTarifas EUR
GBPTarifas GBP
IDRTarifas IDR
INRTarifas INR
MXNTarifas MXN
MYRTarifas MYR
PENTarifas PEN
SARTarifas SAR
SGDTarifas SGD

Actualizaciones de las tarjetas de tarifas

Las siguientes tablas muestran actualizaciones futuras de las tarifas. Consulta las tarjetas de tarifas actuales para ver las tarifas vigentes.

Tarifas vigentes desde el 1 de julio de 2026 en 16 monedas:

Moneda¿Lanzada en 2026?Tarifas (CSV)Tarifas (PDF)
USDYa disponibleTarifas USDTarifas USD
AEDSí – 1 de abril de 2026Tarifas AEDTarifas AED
ARSSí – 1 de abril de 2026Tarifas ARSTarifas ARS
AUDYa disponibleTarifas AUDTarifas AUD
BRLSí – 1 de julio de 2026Tarifas BRLTarifas BRL
CLPSí – 1 de abril de 2026Tarifas CLPTarifas CLP
COPSí – 1 de abril de 2026Tarifas COPTarifas COP
EURYa disponibleTarifas EURTarifas EUR
GBPYa disponibleTarifas GBPTarifas GBP
IDRYa disponibleTarifas IDRTarifas IDR
INRYa disponibleTarifas INRTarifas INR
MXNSí – 1 de enero de 2026Tarifas MXNTarifas MXN
MYRSí – 1 de abril de 2026Tarifas MYRTarifas MYR
PENSí – 1 de abril de 2026Tarifas PENTarifas PEN
SARSí – 1 de abril de 2026Tarifas SARTarifas SAR
SGDSí – 1 de abril de 2026Tarifas SGDTarifas SGD

Actualizaciones anteriores

  • Vigente desde el 1 de abril de 2026 – 8 nuevas monedas de facturación: AED (Emiratos Árabes Unidos), ARS (Argentina), CLP (Chile), COP (Colombia), MYR (Malasia), PEN (Perú), SAR (Arabia Saudita), SGD (Singapur).
  • Vigente desde el 1 de enero de 2026 – tarifas MXN (México) introducidas.

Cómo las llamadas cambian la ventana de servicio al cliente de 24 horas

Actualmente, cuando un usuario de WhatsApp te envía un mensaje, comienza (o se refresca) un temporizador de 24 horas llamado ventana de servicio al cliente.

Cuando estás dentro de la ventana, tu negocio puede enviar cualquier tipo de mensaje al usuario de WhatsApp, algo que no está permitido de otra forma.

Con la introducción de la Calling API, la ventana de servicio al cliente ahora también comienza o se refresca con las llamadas:

  • Cuando un usuario de WhatsApp te llama, sin importar si aceptas la llamada o no.
  • Cuando un usuario de WhatsApp acepta tu llamada.

Obtener costos y estadísticas de llamadas

Obtén las estadísticas de llamadas de tu cuenta de WhatsApp Business (WABA), con información útil como costo, conteos de llamadas completadas y duración promedio de llamadas. Aprende más sobre call analytics.

Endpoint: GET /calls/{v}/{did}/analytics

Response (200):

{
  "call_analytics": {
    "data": [
      {
        "data_points": [
          {
            "start": 1676361600,
            "end": 1676448000,
            "cost": 10,
            "count": 10,
            "average_duration": 1
          }
        ]
      }
    ]
  },
  "id": "114525791557199"
}

Filtros:

CampoTipoDescripción
start / endEnteroRango de fechas (Unix timestamp). Requerido.
granularityEnumeraciónHALF_HOUR, DAILY o MONTHLY. Requerido.
country_codesCadena[]Países a incluir (códigos de dos letras). Opcional.
phone_numbersCadena[]Números de teléfono comerciales a incluir. Opcional.
metric_typesEnumeraciónCOST, COUNT, AVERAGE_DURATION. Opcional.
directionsEnumeraciónUSER_INITIATED, BUSINESS_INITIATED. Opcional.
dimensionsEnumeraciónDIRECTION, COUNTRY, PHONE. Opcional.

Especificaciones SIP

El Protocolo de Inicio de Sesión (SIP) es un protocolo de señalización usado para iniciar, mantener, modificar y terminar sesiones de comunicación en tiempo real entre dos o más endpoints. La API de Calling soporta usar SIP como protocolo de señalización en lugar de los endpoints de la Graph API.

Precaución: al habilitar SIP en un número de teléfono comercial, no puedes usar los endpoints de la Graph API relacionados con llamadas. Por defecto, no se envían webhooks relacionados con llamadas, pero puedes habilitar la entrega de webhooks para llamadas SIP con webhook_delivery para recibir eventos del ciclo de vida.

Arquitectura de señalización SIP

Requisitos previos:

  • La aplicación debe estar habilitada para llamadas (firma del contrato Beta).
  • La aplicación debe tener permisos de mensajería en el número de teléfono comercial. Prueba enviando y recibiendo mensajes con los endpoints de Graph API, y usa la misma app para configurar tu servidor SIP. Verifica con la Health Status API.
  • El modo de la aplicación debe ser “En vivo” (no “En desarrollo”).
  • Un servidor SIP de terceros compatible con estándares que soporte transporte TLS y autenticación digest.

Seguridad:

  • El transporte TLS es obligatorio para SIP. Meta presenta un certificado de servidor válido cuyo nombre de sujeto cubre el dominio SIP wa.meta.vc. Tu servidor SIP debe hacer lo mismo: Meta valida que tu certificado sea válido y que el nombre de sujeto cubra el dominio SIP configurado en el número.
  • Meta no soporta TLS mutuo (mTLS): cuando Meta actúa como cliente TLS, tu servidor TLS no debe solicitar certificado de cliente. Si lo solicitas, Meta presentará un certificado de cliente cuyo sujeto referencia un host dinámico aleatorio que no pasará la validación.
  • Meta agrega transport=TLS a la URI de solicitud en sus solicitudes SIP a tu servidor.
  • Para llamadas iniciadas por el negocio, el INVITE SIP de tu servidor será desafiado con autenticación digest.
  • Para llamadas iniciadas por el usuario, se recomienda fuertemente desafiar el INVITE SIP de Meta con autenticación digest.

Configurar los ajustes SIP

Endpoint: POST /calls/{v}/{did}/settings

Request:

{
  "calling": {
    "status": "ENABLED",
    "sip": {
      "status": "ENABLED",
      "webhook_delivery": "ENABLED",
      "servers": [
        {
          "hostname": "sip.example.com",
          "port": 5061,
          "request_uri_user_params": {
            "tgrp": "meta-wa",
            "trunk-context": "byoc.example.com"
          }
        }
      ]
    }
  }
}

Response (200):

{
  "success": true
}

Campos de sip:

CampoDescripción
statusENABLED o DISABLED (default). Al habilitar, el número usa exclusivamente SIP para señalización y no funciona con las APIs Graph. Al deshabilitar, los servidores SIP no se restablecen; al volver a habilitar se aplican los configurados previamente. Puedes configurar status y servers en la misma solicitud.
webhook_deliveryENABLED o DISABLED (default). Cuando está ENABLED, los webhooks del ciclo de vida de llamadas SIP (call_created y terminate) se envían a tu endpoint de webhook configurado. Solo aplica cuando status es ENABLED.
serversConfiguración de ruteo del servidor SIP. Cada número puede tener solo un servidor SIP configurado (el campo es un array por compatibilidad futura). Meta antes permitía múltiples apps cada una con su servidor SIP, pero eso ya no funciona porque Meta termina la llamada tras recibir BYE de cualquiera de los servidores. La app asociada se extrae del access token usado. Para eliminar un servidor, envía el campo con un array vacío. Se requiere al menos un servidor SIP de alguna app cuando status es ENABLED.
servers[].hostnameNombre de host del servidor SIP. Las solicitudes deben usar TLS.
servers[].portPuerto del servidor SIP que acepta solicitudes. Debe usar TLS. Default 5061.
servers[].request_uri_user_paramsParámetros opcionales incluidos en la sección de usuario de la URI de solicitud del INVITE SIP de Meta (ej. grupos troncales, RFC 4904). Clave o valor limitados a 128 caracteres. Ej: sip:+1234567890;tgrp=wacall;trunk-context=byoc.example.com@sip.example.com
:—-:—-
sip.statusENABLED o DISABLED (default). Al deshabilitar, los servidores SIP no se restablecen; al volver a habilitar se aplican los configurados previamente.
sip.serversMáximo un servidor SIP por aplicación. Para eliminar un servidor, envía el campo con una matriz vacía.
sip.server.hostnameNombre de host del servidor SIP para recibir solicitudes SIP por TLS.
sip.server.portPuerto del servidor SIP por TLS. Default 5061.
sip.server.request_uri_user_paramsParámetros que Meta incluye en la sección de usuario de la URI de solicitud (ej. grupos troncales, RFC 4904). Clave o valor limitados a 128 caracteres.

Ejemplo con curl:

curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/settings' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "calling": {
      "status": "ENABLED",
      "sip": {
        "status": "ENABLED",
        "servers": [{
          "hostname": "{SIP_SERVER_URL}"
        }]
      }
    }
  }'

Obtener la configuración SIP

La contraseña del usuario SIP se incluye solo si se especifica el query param include_sip_credentials=true.

Endpoint: GET /calls/{v}/{did}/settings?include_sip_credentials=true

Response (200):

{
  "calling": {
    "status": "ENABLED",
    "call_icon_visibility": "DEFAULT",
    "callback_permission_status": "ENABLED",
    "sip": {
      "status": "ENABLED",
      "servers": [
        {
          "app_id": "<APP_ID_THAT_CONFIGURED_THIS_SIP_SERVER>",
          "hostname": "sip.example.com",
          "sip_user_password": "{SIP_USER_PASSWORD}"
        }
      ]
    }
  }
}

Nota: el campo sip_user_password solo se incluye si se agregó el query param include_sip_credentials=true. La respuesta de GET incluye app_id, que identifica la app que configuró ese servidor SIP.

Restablecer la contraseña SIP

Para hacer que Meta genere una nueva contraseña SIP:

  1. Deshabilita SIP y borra el servidor SIP.
  2. Vuelve a habilitar SIP y agrega el servidor.
  3. Consulta la configuración SIP con include_sip_credentials=true para ver la nueva contraseña.
# Deshabilitar y borrar
curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/settings' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "calling": {
      "status": "DISABLED",
      "sip": {
        "status": "DISABLED",
        "servers": []
      }
    }
  }'
# Habilitar y agregar
curl --request POST \
  --url 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/settings' \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '{
    "calling": {
      "status": "ENABLED",
      "sip": {
        "status": "ENABLED",
        "servers": [{"hostname": "sip.example.com"}]
      }
    }
  }'

Encabezados SIP personalizados

Los siguientes encabezados SIP personalizados son comunes a las llamadas iniciadas por el negocio y por el usuario:

EncabezadoMetadatosDescripción
x-wa-meta-call-durationOpcional; StringDuración de la llamada en segundos. Presente en las solicitudes BYE de Meta para la terminación de una llamada establecida.
x-wa-meta-wacidOpcional; StringID de la llamada de WhatsApp. Presente en el INVITE SIP de Meta (llamada iniciada por el usuario) y en las solicitudes BYE de Meta.
x-wa-meta-user-idOpcional; StringBSUID del usuario de WhatsApp. Presente en los mensajes SIP de Meta (INVITE, 200 OK, BYE) cuando el negocio tiene BSUID habilitados.
x-wa-meta-parent-user-idOpcional; StringParent BSUID del usuario, si los parent BSUID están habilitados para el negocio.
x-wa-meta-usernameOpcional; StringUsername del usuario, si adoptó uno.

Los siguientes encabezados son específicos de las llamadas iniciadas por el usuario:

EncabezadoMetadatosDescripción
x-wa-meta-cta-payloadOpcional; StringPresente cuando el usuario inicia una llamada desde un botón de llamada con payload de negocio.
x-wa-meta-deeplink-payloadOpcional; StringPresente cuando el usuario inicia una llamada desde un call deeplink con payload de negocio.

Webhooks de llamadas SIP

Las llamadas SIP ahora soportan webhooks, proporcionando eventos del ciclo de vida a tu endpoint de webhook cuando habilitas la entrega en un número con SIP.

WebhookDescripción
Call createdEnviado cuando se intenta una llamada SIP.
Call terminateEnviado cuando la llamada termina por cualquier razón.

Estos webhooks aplican tanto a llamadas SIP iniciadas por el negocio como por el usuario.

Requisitos previos:

  1. Suscríbete al campo de webhook calls.
  2. Habilita SIP en el número de teléfono comercial.
  3. Habilita la entrega de webhooks para llamadas SIP con webhook_delivery: ENABLED en los ajustes SIP (deshabilitado por defecto).

Nota sobre el mapeo del ID de llamada: el campo id del payload del webhook contiene el ID de llamada de WhatsApp (WACID). Este WACID puede correlacionarse con el encabezado SIP personalizado x-wa-meta-wacid en los mensajes SIP para mapear los eventos del webhook a sesiones de llamada SIP específicas.

Nota: los webhooks SIP no incluyen información SDP, porque el servidor SIP maneja la media. Son informativos, para mantener tu sistema de mensajería informado sobre los eventos del ciclo de vida de la llamada.

Webhook de llamada creada (call_created):

{
  "object": "whatsapp_business_account",
  "entry": [
    {
      "id": "<WHATSAPP_BUSINESS_ACCOUNT_ID>",
      "changes": [
        {
          "value": {
            "messaging_product": "whatsapp",
            "metadata": {
              "display_phone_number": "16315553601",
              "phone_number_id": "<PHONE_NUMBER_ID>"
            },
            "contacts": [
              {
                "profile": {
                  "name": "<CALLEE_NAME>",
                  "username": "<USERNAME>"
                },
                "wa_id": "16315553602",
                "user_id": "<BSUID>",
                "parent_user_id": "<PARENT_BSUID>"
              }
            ],
            "calls": [
              {
                "id": "wacid.ABGGFjFVU2AfAgo6V-Hc5eCgK5Gh",
                "to": "16315553601",
                "to_user_id": "<BSUID>",
                "to_parent_user_id": "<PARENT_BSUID>",
                "from": "16315553602",
                "event": "call_created",
                "timestamp": "1671644824",
                "direction": "BUSINESS_INITIATED"
              }
            ]
          },
          "field": "calls"
        }
      ]
    }
  ]
}

Las descripciones de los campos de calls son las mismas que las del webhook Connect, con la excepción de que los webhooks de llamadas SIP no incluyen el objeto session, porque la señalización se maneja vía SIP en lugar de WebRTC.

Autenticación digest en llamadas iniciadas por la empresa

El primer INVITE SIP a Meta falla con 407 Proxy Authentication required. Debes enviar un segundo INVITE con el encabezado de autorización adecuado.

Requisitos:

  • El atributo de nombre de usuario del campo de autorización debe coincidir con el nombre de usuario del encabezado From (el número de teléfono comercial normalizado).
  • El dominio del encabezado From debe coincidir con el servidor SIP configurado en el número de teléfono comercial.
  • Se requiere la aprobación de permiso de llamada del usuario.
  • La oferta SDP debe ser compatible con ICE, DTLS-SRTP y OPUS (esencialmente medios WebRTC).

Validar el certificado TLS

El servidor SIP de Meta valida el certificado TLS del hostname configurado. Un certificado cuyo hostname no coincida (por ejemplo, usar un hostname de un proveedor distinto al configurado en el número) provoca un error de validación hostname mismatch y no se recibirá tráfico SIP de Meta.

Para evitar el problema, configura el hostname del servidor SIP de forma que coincida con el certificado presentado, y usa request_uri_user_params (por ejemplo tgrp y trunk-context) cuando el proveedor lo requiera para enrutar el tráfico.

Solicitudes SIP de muestra

INVITE WebRTC Media

INVITE sip:17015558857@meta-voip.example.com SIP/2.0
Via: SIP/2.0/TLS [2803:6080:e888:51aa:d4a4:c5e0:300:0]:33819;branch=z9hG4bKPjNvs.IZBnUa1W4l8oHPpk3SUMmcx3MMcE;alias
Max-Forwards: 70
From: "12195550714" <sip:12195550714@wa.meta.vc>;tag=bbf1ad6e-79bb-4d9c-8a2c-094168a10bea
To: <sip:17015558857@meta-voip.example.com>
Contact: <sip:12195550714@wa.meta.vc;transport=tls;ob>;isfocus
Call-ID: outgoing:wacid.HBgLMTIxOTU1NTA3MTQVAgASGCAzODg1NTE5NEU1NTBEMTc1RTFFQUY5NjNCQ0FCRkEzRhwYCzE3MDE1NTU4ODU3FQIAAA==
CSeq: 2824 INVITE
X-FB-External-Domain: wa.meta.vc
Allow: INVITE, ACK, BYE, CANCEL, NOTIFY, OPTIONS
User-Agent: Facebook SipGateway
Content-Type: application/sdp

v=0
o=- 1741113186367 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
m=audio 3480 UDP/TLS/RTP/SAVPF 111 126
a=ice-lite
a=setup:actpass
a=mid:audio
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000
a=ptime:20
a=maxptime:20
a=ssrc:849255537 cname:WhatsAppAudioStream1

INVITE con autenticación digest (llamadas iniciadas por el usuario)

Primera INVITE:

INVITE sip:+12145551869@meta-voip.example.com;transport=tls SIP/2.0
From: "12195550714" <sip:+12195550714@wa.meta.vc>;tag=ece2da15-39e7-4983-ac65-e312f325d94a
To: <sip:+12145551869@meta-voip.example.com>
Call-ID: outgoing:wacid.HBgLMTIxOTU1NTA3MTQVAgASGCA2MUI2QUY0MDRCMTUyOTM4QkE5ODEwN0ZGQTAwODkxORwYCzEyMTQ1NTUxODY5FQIAFRoA
CSeq: 9989 INVITE
Content-Type: application/sdp

v=0
o=- 1750716867913 2 IN IP4 127.0.0.1
s=-
t=0 0
m=audio 3480 RTP/SAVP 111 126
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000
a=ptime:20
a=maxptime:20
a=ssrc:215879358 cname:WhatsAppAudioStream1

Respuesta 407 del servidor SIP:

SIP/2.0 407 Proxy Authentication required
CSeq: 9989 INVITE
Call-ID: outgoing:wacid.HBgLMTIxOTU1NTA3MTQVAgASGCA2MUI2QUY0MDRCMTUyOTM4QkE5ODEwN0ZGQTAwODkxORwYCzEyMTQ1NTUxODY5FQIAFRoA
From: "12195550714" <sip:+12195550714@wa.meta.vc>;tag=ece2da15-39e7-4983-ac65-e312f325d94a
To: <sip:+12145551869@meta-voip.example.com>;tag=45065608_c3356d0b_16001fd8-76d2-45f0-bb35-e0441d6dc4a2
Proxy-Authenticate: Digest realm="sip.twilio.com",nonce="eyOam_8-l5FVugxsyxFRjnlxq9vy1TjQIMB3mBfJuAvB5gV4",opaque="4a6a068be2ca2032a57912b9a2a6adf7",qop="auth"
Content-Length: 0

Segunda INVITE con autorización:

INVITE sip:+12145551869@meta-voip.example.com;transport=tls SIP/2.0
From: "12195550714" <sip:+12195550714@wa.meta.vc>;tag=ece2da15-39e7-4983-ac65-e312f325d94a
To: <sip:+12145551869@meta-voip.example.com>
Call-ID: outgoing:wacid.HBgLMTIxOTU1NTA3MTQVAgASGCA2MUI2QUY0MDRCMTUyOTM4QkE5ODEwN0ZGQTAwODkxORwYCzEyMTQ1NTUxODY5FQIAFRoA
CSeq: 9990 INVITE
Proxy-Authorization: Digest username="12145551869", realm="sip.twilio.com", nonce="eyOam_8-l5FVugxsyxFRjnlxq9vy1TjQIMB3mBfJuAvB5gV4", uri="sip:+12145551869@meta-voip.example.com", response="b28ed6b8bf1418e3c6eca05ef8c7a0b1", cnonce="TY2SszvYCKitUCBlVLpGiPKMQfmBbj", opaque="4a6a068be2ca2032a57912b9a2a6adf7", qop=auth, nc=00000001
Content-Type: application/sdp

v=0
o=- 1750716867913 2 IN IP4 127.0.0.1
s=-
t=0 0
m=audio 3480 RTP/SAVP 111 126
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000
a=ptime:20
a=maxptime:20
a=ssrc:215879358 cname:WhatsAppAudioStream1

OK del servidor SIP:

SIP/2.0 200 OK
CSeq: 9990 INVITE
Call-ID: outgoing:wacid.HBgLMTIxOTU1NTA3MTQVAgASGCA2MUI2QUY0MDRCMTUyOTM4QkE5ODEwN0ZGQTAwODkxORwYCzEyMTQ1NTUxODY5FQIAFRoA
From: "12195550714" <sip:+12195550714@wa.meta.vc>;tag=ece2da15-39e7-4983-ac65-e312f325d94a
To: <sip:+12145551869@meta-voip.example.com>;tag=29360930_c3356d0b_4933dc58-f035-4597-b075-04b19e552329
Content-Type: application/sdp
Content-Length: 444

v=0
o=root 477560318 477560318 IN IP4 172.18.156.61
s=Twilio Media Gateway
t=0 0
m=audio 12710 RTP/SAVP 111 126
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000
a=ptime:20
a=maxptime:20
a=sendrecv

Resolución de problemas

ProblemaCausaSolución
No se recibe tráfico SIP de MetaCertificado TLS con hostname mismatchConfigura el hostname del servidor SIP para que coincida con el certificado presentado.
INVITE falla con 403El servidor SIP del INVITE no coincide con el configurado para el númeroVerifica el hostname configurado en el número de teléfono.
407 Proxy Authentication requiredAutenticación digest faltanteEnvía un segundo INVITE con el encabezado de autorización correcto.

SDES (intercambio de claves SRTP)

Puedes configurar el protocolo de intercambio de claves SRTP como SDES en lugar del DTLS predeterminado.

Habilitar/deshabilitar SDES

Endpoint: POST /calls/{v}/{did}/settings

Request:

{
  "calling": {
    "status": "ENABLED",
    "call_icon_visibility": "DEFAULT",
    "srtp_key_exchange_protocol": "SDES"
  }
}

Response (200):

{
  "success": true
}

Notas:

  • srtp_key_exchange_protocol es opcional, con DTLS como valor predeterminado. Configúralo como SDES para usar SDES.
  • Solo se permite el uso de SDES para números con SIP habilitado.
  • Meta aún espera que el lado comercial envíe el paquete SRTP inaugural, tanto para llamadas iniciadas por el usuario como por la empresa.

Obtener el protocolo de intercambio de claves

Endpoint: GET /calls/{v}/{did}/settings

El campo srtp_key_exchange_protocol está ausente si el socio no lo configuró explícitamente.

SDP overview y estructuras de muestra

El Protocolo de Descripción de Sesión (SDP) es un formato de texto que describe las características de las sesiones multimedia (voz y video) en aplicaciones de comunicación en tiempo real: tipo de media, códecs, protocolos y parámetros. En WebRTC, el SDP se usa para negociar los parámetros de media entre emisor y receptor.

Estructuras de muestra para llamadas iniciadas por el negocio

SDP offer

v=0
o=- 3626166318745852955 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS d8b26053-4474-4eb7-b3c3-c93d6c8c9b2e
m=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 110 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:4g1c
a=ice-pwd:qY/Bb+jQzg5ICn6X4fhJQetk
a=ice-options:trickle
a=fingerprint:sha-256 35:47:24:24:9F:93:C4:3E:DB:37:7F:BB:ED:F8:20:B5:AD:AC:DC:35:C2:7D:67:EE:6C:35:54:DF:A6:00:5C:4A
a=setup:actpass
a=mid:0
a=extmap:1 urn:ietf:params:rtp-hdrext:ssrc-audio-level
a=extmap:2 http://www.webrtc.org/experiments/rtp-hdrext/abs-send-time
a=extmap:3 http://www.ietf.org/id/draft-holmer-rmcat-transport-wide-cc-extensions-01
a=extmap:4 urn:ietf:params:rtp-hdrext:sdes:mid
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtcp-fb:111 transport-cc
a=fmtp:111 minptime=10;useinbandfec=1
a=rtpmap:63 red/48000/2
a=fmtp:63 111/111
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000

SDP answer (de Meta)

v=0
o=- 741807839102053725 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE 0
a=extmap-allow-mixed
a=msid-semantic: WMS 798a9670-c0d6-47a8-925e-5f082ef4d8a0
a=ice-lite
m=audio 3482 UDP/TLS/RTP/SAVPF 111 9 0 8 110 126
c=IN IP4 31.13.65.130
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:2754936280 1 udp 2113937151 31.13.65.130 3482 typ host generation 0 network-cost 50 ufrag JHqAXFH4HcAY/8
a=ice-ufrag:JHqAXFH4HcAY/8
a=ice-pwd:dNNMmR8wUcGezvfBZOO0Qgcwl2m86GP/
a=ice-options:trickle
a=fingerprint:sha-256 9C:97:5C:4C:A9:BE:9E:2F:06:94:F5:BB:38:2C:A1:29:B5:69:B8:FA:94:10:56:1D:0B:5D:80:28:C1:FD:F0:F6
a=setup:active
a=mid:0
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:9 G722/8000
a=rtpmap:0 PCMU/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:110 telephone-event/48000
a=rtpmap:126 telephone-event/8000

Estructuras de muestra para llamadas iniciadas por el usuario

SDP offer (de Meta)

v=0
o=- 7602563789789945080 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS 6932bc1c-db1a-4abe-b437-0c4168be8a13
a=ice-lite
m=audio 40012 UDP/TLS/RTP/SAVPF 111 126
c=IN IP4 31.13.65.60
a=rtcp:9 IN IP4 0.0.0.0
a=candidate:1972637320 1 udp 2113937151 31.13.65.60 40012 typ host generation 0 network-cost 50 ufrag 6k2qP1R6kBfI/2
a=ice-ufrag:6k2qP1R6kBfI/2
a=ice-pwd:UApvJw3NcwFRDvIMKdM0vWCdlXah25E9
a=fingerprint:sha-256 1B:B6:6B:40:A5:0B:8C:75:0D:8C:CB:90:2F:99:74:1E:26:45:AE:AF:45:C1:51:60:8F:73:C9:2D:10:6D:8A:88
a=setup:actpass
a=mid:audio
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000

SDP answer

v=0
o=- 2822644248144643933 2 IN IP4 127.0.0.1
s=-
t=0 0
a=group:BUNDLE audio
a=msid-semantic: WMS eb909cf0-87f0-4358-a4c9-7861680d9431
m=audio 9 UDP/TLS/RTP/SAVPF 111 126
c=IN IP4 0.0.0.0
a=rtcp:9 IN IP4 0.0.0.0
a=ice-ufrag:X1ho
a=ice-pwd:7fJSbV2N5qWiA5QiDKwK3vuh
a=fingerprint:sha-256 2E:35:9F:21:9E:63:72:E5:42:74:76:2D:B3:70:F7:CB:24:14:9B:14:52:71:05:48:DA:4D:67:31:09:58:2A:ED
a=setup:active
a=mid:audio
a=sendrecv
a=rtcp-mux
a=rtpmap:111 opus/48000/2
a=rtpmap:126 telephone-event/8000

Ejemplos de solicitudes cURL

Nota: el did en estas solicitudes corresponde al ID del número de teléfono del negocio.

Iniciar una nueva llamada

curl -i -X POST 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/signaling' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
     "messaging_product": "whatsapp",
     "to": "14085550000",
     "recipient": "US.13491208655302741918",
     "action": "connect",
     "session": {
         "sdp": "v=0\no=- 7669997803033704573 2 IN IP4 127.0.0.1\ns=-\nt=0 0\na=group:BUNDLE 0\na=msid-semantic: WMS 3c28addc-03b7-4170-b5cd-535bfe767e75\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 110 126\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-ufrag:6O0H\na=ice-pwd:TYCbtfOrBMPpfxFRgSbYnuTI\na=ice-options:trickle\na=fingerprint:sha-256 9F:45:2C:A8:C3:C0:CC:9B:59:4F:D1:02:56:52:FA:36:00:BE:C0:79:87:B3:D9:9C:3E:BF:60:98:25:B4:26:FC\na=setup:active\na=mid:0\na=sendrecv\na=rtcp-mux\na=rtpmap:111 opus/48000/2\na=fmtp:111 minptime=10;useinbandfec=1\na=rtpmap:63 red/48000/2\na=rtpmap:9 G722/8000\na=rtpmap:0 PCMU/8000\na=rtpmap:8 PCMA/8000\na=rtpmap:126 telephone-event/8000\n",
         "sdp_type": "offer"
     }
}'

Terminar una llamada

curl -i -X POST 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/signaling' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
     "messaging_product": "whatsapp",
     "action": "terminate",
     "call_id": "wacid.HBgLMTY1MDMxMzM5NzQVAgARGCBFRjNEODRBM0Q3NDZDM0Q0QzI4MzAwQjZBRkZGODM3NhwYCzEyMjQ1NTU0NDg5FQIAAA"
}'

Aceptar una llamada

curl -i -X POST 'https://channels.chattigo.com/bsp-cloud-chattigo-isv/calls/v21.0/{did}/signaling' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
     "messaging_product": "whatsapp",
     "to": "14085550000",
     "action": "accept",
     "call_id": "wacid.HBgLMTY1MDMxMzM5NzQVAgASGCA5ODkyMDk2RkM2NUM1QTYwRkM4NjFDQzk0NkQwNDBCRRwYCzEyMjQ1NTU0NDg5FQIAAA==",
     "session": {
         "sdp": "v=0\no=- 7669997803033704573 2 IN IP4 127.0.0.1\ns=-\nt=0 0\na=group:BUNDLE 0\na=msid-semantic: WMS 3c28addc-03b7-4170-b5cd-535bfe767e75\nm=audio 9 UDP/TLS/RTP/SAVPF 111 63 9 0 8 110 126\nc=IN IP4 0.0.0.0\na=rtcp:9 IN IP4 0.0.0.0\na=ice-ufrag:6O0H\na=ice-pwd:TYCbtfOrBMPpfxFRgSbYnuTI\na=ice-options:trickle\na=fingerprint:sha-256 9F:45:2C:A8:C3:C0:CC:9B:59:4F:D1:02:56:52:FA:36:00:BE:C0:79:87:B3:D9:9C:3E:BF:60:98:25:B4:26:FC\na=setup:active\na=mid:0\na=sendrecv\na=rtcp-mux\na=rtpmap:111 opus/48000/2\na=fmtp:111 minptime=10;useinbandfec=1\na=rtpmap:63 red/48000/2\na=rtpmap:9 G722/8000\na=rtpmap:0 PCMU/8000\na=rtpmap:8 PCMA/8000\na=rtpmap:126 telephone-event/8000\n",
         "sdp_type": "answer"
     }
}'

Registros de llamadas

La pestaña Call Logs en WhatsApp Manager proporciona una vista detallada de los eventos de llamada para ayudar en el troubleshooting.

Para verlos: WhatsApp Manager > Account tools > Phone numbers > selecciona el número.

CampoDescripción
TimestampMarca de tiempo de la llamada.
Call DirectionOutbound (iniciada por el negocio) o Inbound (iniciada por el usuario).
SignalingProtocolo de señalización usado (SIP, GRAPH_API).
Call IDIdentificador de la llamada de WhatsApp. Proporciona este ID al solicitar soporte.
Request IDIdentificador del request que inició la llamada.
Call DetailsInformación adicional con un log de eventos durante el ciclo de vida de la llamada.

Errores SIP

Llamadas iniciadas por el negocio

Estado y mensaje SIPDescripciónPosibles soluciones
400 — Asset not found, invalid business phone numberEl número en el header From del INVITE es inválido y no corresponde a una cuenta registrada.Verifica el número y reenvía el INVITE con el From correcto.
403 — SIP server foo.com from INVITE does not match any SIP server configured for phone number id [ID]El From de tu INVITE a Meta tiene foo.com, pero no hay un servidor SIP con ese hostname configurado en el número.Asegura que la configuración SIP coincida con el dominio usado en el From. El hostname de la configuración debe coincidir con el dominio del From, o ser un subdominio de este.
403 — No Approved Call Permission FoundNo hay un usuario de WhatsApp con ese número, no aceptó los términos, o no hay permiso del usuario para llamar al negocio.Doble verifica el número y obtén el permiso del usuario.
403 — The app [APP_ID] configured for SIP server example.com is not authorized for phone number id [ID]La app mapeada al servidor SIP no tiene permiso whatsapp_business_messaging en el número.Verifica que uses la app correcta con permisos en el número. Puede que debas borrar y agregar el servidor SIP con la app correcta.
403 — Business Initiated Connected Call Per Day Limit HitLímite de llamadas iniciadas por el negocio en 24h.Ajusta la tasa de llamadas según los límites.
404 — Not foundNo se permiten INVITEs SIP usando IP en la request URI.Usa la request URI correcta.
407 — Proxy Authentication RequiredMeta exige autenticación digest para tus INVITEs SIP.Reenvía el INVITE con la respuesta digest.
408 — RTP TimeoutEl cliente terminó la llamada por no recibir media por mucho tiempo.Ver los issues de media.
480 — Temporarily UnavailableEl usuario de WhatsApp no es alcanzable o no respondió.Reintenta más tarde. Las llamadas sin respuesta impactan los permisos.
486 — User declined the callEl usuario rechazó la llamada.Reintenta más tarde. Las llamadas rechazadas impactan los permisos.
487 — Request TerminatedEl negocio canceló su INVITE SIP con SIP CANCEL.Esperado cuando cancelas el INVITE antes de la respuesta de Meta.
503 — Service UnavailableError interno genérico.Reintenta después de un tiempo o consulta el soporte de Meta.

Problemas de media

ProblemaDescripciónPosibles soluciones
La llamada se corta a los 20 segundosAl inicio de la llamada, si no fluye media del negocio al usuario por 20 segundos, el cliente corta.Verifica que tu servidor de media inicie la sesión y envíe paquetes; revisa tu firewall; captura tráfico de red (pcap) para el soporte.
No se escucha audio y la llamada se corta a los 30 segundosDespués de conectarse, si no hay media del negocio al usuario por 30 segundos, el cliente corta.Envía al menos paquetes RTCP incluso en silencio o cuando esperas input del usuario (ej. IVR); revisa por qué tu servidor deja de enviar media; captura tráfico de red (pcap).

Problema y solución del recorte de audio

El recorte de audio se explica en detalle en Mejores prácticas de integración. Además de la aceptación optimista (pre-accept), las soluciones alternativas incluyen:

  • Usar SDES: configura SDES en tu número de negocio en lugar de DTLS. Una razón común del retraso en el establecimiento del tramo de media es la finalización del handshake DTLS. Con SDES puedes enviar SRTP directamente después de enviar el SDP a Meta.
  • Reproducción de audio retrasada: instruye al SIP UA a esperar un ACK de BizWebrtcEndpoint antes de reproducir audio.
  • Retraso basado en el estado de conexión: dirige al SIP UA a esperar hasta que el estado de conexión WebRTC sea connected antes de reproducir audio.
  • Paquetes de media en búfer: almacena los paquetes de media SIP y envíalos solo después de establecer la conexión WebRTC.
  • Inserción de silencio: inserta un breve período de silencio en el audio del IVR antes del contenido real.
  • Pre-accept: invoca el pre-accept incluso antes de enviar el INVITE SIP (aceptación optimista).

Soporte

Para soporte de la API de WhatsApp Business Calling, elige el tema WaBiz: Calling API al abrir un ticket en Direct Support.

Guía de revisión de apps (App Review)

Nota: los revisores usan la página de referencia de permisos como fuente oficial. Usa esta guía como complemento, pero trata la página de referencia de permisos como la fuente oficial en caso de duda.

Esta página brinda detalles para mejorar tus posibilidades de una App Review exitosa específicamente para las funciones de la API de WhatsApp Business Calling.

Para el permiso WhatsApp Business management

Debes mostrar claramente que tu app puede habilitar y deshabilitar las funciones de la Calling API mostrando si el ícono del botón de llamada es visible.

Comparte un video donde habilites y deshabilites el ícono del botón de llamada para la cuenta de WhatsApp Business, ya sea mediante una solicitud cURL o mediante la configuración dentro de la UI de tu aplicación.

Demuestra esto habilitando y deshabilitando las funciones de la Calling API, no solo alternando la visibilidad del ícono del botón de llamada.

Ejemplo

  1. Muestra un hilo de chat entre tu negocio y un usuario de WhatsApp que no tiene el ícono del botón de llamada.
  2. Usa tu app para habilitar las funciones de la Calling API en el número de teléfono del negocio, lo que muestra el ícono del botón de llamada.
  3. Vuelve al mismo hilo de chat y muestra que el ícono del botón de llamada es visible.

Para el permiso WhatsApp Business messaging

Debes demostrar claramente que tu aplicación soporta cualquiera de los siguientes casos de uso:

Caso de uso 1: Realizar una llamada iniciada por el negocio

Comparte un video que muestre a tu aplicación realizando una llamada iniciada por el negocio. Luego muestra a un usuario aceptando la llamada en un cliente móvil de WhatsApp.

Caso de uso 2: Recibir una llamada iniciada por el usuario

Comparte un video que muestre a un usuario realizando una llamada al número de teléfono de tu negocio. Luego muestra a tu aplicación recibiendo la llamada entrante.

Muestra cualquiera de las siguientes opciones:

  1. La llamada entrante en la UI de la aplicación cliente de WhatsApp.
  2. El webhook de llamadas que la plataforma de WhatsApp entrega a tu app.

Preguntas frecuentes

Preguntas frecuentes del producto

¿Las llamadas aparecerán en la página de insights de WhatsApp Manager de Meta?

Los insights de llamadas estarán disponibles tanto en WhatsApp Manager como en la API de analíticas.

¿Se soportan las llamadas internacionales como las llamadas de WhatsApp de consumidor a consumidor?

Sí.

¿Cuáles son los países soportados para llamadas?

Consulta Disponibilidad de llamadas para más información.

¿Puedo usar números gratuitos (toll-free) para llamadas?

Sí, siempre que el código de país del número gratuito esté en la lista de países soportados. Consulta 1-800 y números gratuitos para saber cómo registrar números gratuitos en la Cloud API.

¿Cuál es el número máximo de llamadas concurrentes que puede recibir un único número de teléfono de una cuenta de Cloud API?

El máximo de llamadas concurrentes es 1000. Cuando se supera el límite, el llamador (el usuario de WhatsApp) recibirá un mensaje genérico indicando que no se puede realizar la llamada. No se reproduce ningún mensaje ni se envía webhook. Se espera que este límite aumente, por lo que las probabilidades de que ocurra son bajas. Ten en cuenta que los límites de la API de mensajería y de la API de creación/actualización de plantillas son independientes y no están relacionados con los límites de llamadas.

¿Cuál es el rol del Solution Partner frente al negocio final en el flujo general de llamadas?

  • El Solution Partner ofrece servicios adicionales como contact center, grabación de voz y transcripción sobre el flujo de audio en bruto proporcionado por Cloud API Calling.
  • El webhook se envía a las apps suscritas al nuevo campo de suscripción calls. En los casos típicos, un Solution Partner usa su propia app y recibe el webhook de llamadas seguido del establecimiento de la llamada.
  • Cómo participa el negocio final en la llamada lo determina el Solution Partner.

¿La infraestructura/API de voz de WhatsApp es la misma que la de Facebook Messenger?

WhatsApp Calling API es la primera API de voz pública de Meta. Meta puede reutilizar la misma API y modelo de integración para otros productos de Meta si y cuando ofrezcan soluciones de voz.

¿Cuál es la duración máxima de llamada soportada?

No hay límite de duración de llamada.

¿Se soporta SIP?

Sí. Consulta Configurar y usar la señalización de llamadas mediante SIP.

¿Puedo enviar/recibir mensajes de texto/media mientras hay una llamada en curso?

Sí. La API de mensajes se puede usar mientras hay una llamada en curso.

¿Meta ofrece servicios como grabación de voz, transcripción o buzón de voz?

No.

¿Puedo agregar metadatos (por ejemplo, contexto) como parte de la aceptación de la llamada?

Sí. Consulta el campo biz_opaque_callback_data en la especificación principal de la API. Además, el estado de la conversación existente proporciona contexto importante al agente humano del negocio. El subsistema de enrutamiento de llamadas debe conectar directamente la llamada del consumidor de WhatsApp con el agente correcto del lado del negocio. Esto brinda la mejor experiencia al cliente y evita pasar por un IVR estándar.

¿Cómo puedo aumentar el conocimiento de la función de llamadas entre los usuarios de WhatsApp?

¿Es posible que una IA (por ejemplo un voicebot) tenga una conversación con un cliente directamente a través de una llamada de WhatsApp?

Sí. Meta solo proporciona el flujo de media en bruto y cómo se procesa es totalmente flexible. Muchas empresas usan voicebots automatizados, incluidos bots de IA, para responder llamadas de usuarios de WhatsApp. Muchos productos de IA del mercado ofrecen APIs RTC/Speech y algunos incluso tienen soporte WebRTC nativo. El enfoque de integración es similar a integrar WhatsApp Business Calling con centros de llamadas para IVR o agentes humanos.

Consulta los Términos de la solución de negocio de WhatsApp para conocer las restricciones en los casos de uso de IA.

¿Por qué la pre-aceptación de una llamada iniciada por el usuario inicia el temporizador en el lado del usuario de WhatsApp?

Probablemente porque se envía media antes de que la llamada sea aceptada. Los clientes de WhatsApp tratan una llamada como aceptada por el par si reciben un paquete de media o una señal de aceptación, lo que ocurra primero.

Si no se puede controlar el inicio de la media, acepta la llamada directamente y no uses la pre-aceptación. La pre-aceptación está pensada para iniciar el establecimiento de la conexión de media temprano, pero requiere controlar el momento de la transmisión de media.

¿Existe una página de estado para hacer seguimiento de la salud de las Calling APIs y ver interrupciones o incidentes de servicio?

Sí. Consulta Cloud API Calling en la página de estado de Meta y el historial de incidentes.

Preguntas frecuentes para comenzar

¿Cuál es la versión mínima de Graph API para la Calling API?

La versión mínima de Graph API es v17.0. Consulta el historial general de versiones.

¿Puedo usar el mismo user access token para mensajería y para llamadas?

Sí. Lo que funcione para mensajería debería funcionar para llamadas en general.

¿La WABA necesita tener una línea de crédito adjunta para usar las Calling APIs?

Sí, se requiere una línea de crédito adjunta a la WABA para usar la Calling API.

¿La WABA necesita ser un negocio verificado para llamadas?

No. La verificación de negocio no es un requisito para llamadas, ni tampoco para mensajería.

¿Cómo afecta el uso de las Calling APIs a mis límites de velocidad?

El uso de la Calling API no cuenta para los límites de velocidad de mensajería por ahora. El único límite aplicado actualmente para llamadas es el límite de 1000 llamadas concurrentes, pero esto puede cambiar en el futuro cercano.

¿Es posible que una cuenta de WhatsApp Business esté conectada al Proveedor A para chat y al Proveedor B para voz (es decir, dos apps diferentes suscritas al mismo webhook de la cuenta/número de WhatsApp Business)?

Sí, es posible que dos partners operen un único número de teléfono de WhatsApp Business API con dos soluciones separadas, como chat y llamadas.

Consulta Multi-Solution Conversations para más detalles.

Otra opción es usar un proveedor de voz utilizado por otro Solution Partner. En este caso no se necesita una app de Meta ni ser tech provider en Meta. Esta arquitectura se detalla en la sección Integrar usando un proveedor de voz de terceros.

Preguntas frecuentes de señalización de Graph API

¿Meta proporciona servidores STUN/TURN o infraestructura WebRTC para uso del Solution Partner?

No.

Meta usa ICE-lite y la oferta SDP de Meta siempre tiene una única dirección ipv4 e ipv6 por componente de flujo de datos. La respuesta SDP debe seguir el mismo formato.

Por lo tanto, no es obligatorio usar STUN/TURN para determinar los candidatos ICE.

¿Meta recomienda algún servidor STUN/TURN o infraestructura WebRTC para el Solution Partner?

Meta no tiene recomendaciones. Aquí hay algunas ideas por si resultan útiles.

  • Revisa si hay alguna tecnología VoIP existente y, de ser así, consulta a ese equipo. WebRTC depende de SRTP/SRTCP para la media real, que es el estándar de media VoIP.
  • Usar STUN/TURN funciona bien en una configuración de usuario final con un navegador desde un dispositivo personal. Si la integración con las APIs de voz de Meta implica terminar la media directamente en un dispositivo del usuario final, STUN/TURN, etc., ocurren directamente en ese dispositivo. Pero a menudo la media termina en la infraestructura propia del partner para poder ofrecer servicios como IVR. En esos casos, la infraestructura del Solution Partner puede tener sus propias formas de asignar una IP y puerto para conexiones VoIP, por ejemplo usando VIP detrás de un balanceador de carga.

¿Qué rol ICE debe tomar el agente ICE del lado del negocio?

Siempre toma el rol CONTROLLING, ya que el agente ICE de Meta usa ICE-lite (RFC 8445). Comenzar con el rol CONTROLLED puede hacer que el proceso ICE se detenga y agote el tiempo. Incluso si funciona, llevará más tiempo debido a los múltiples round-trips necesarios para resolver los conflictos de rol.

¿Se pueden agregar más candidatos ICE como parte de la señalización en offer + answer (por ejemplo usando ICE Trickle)?

La respuesta corta es sí. Cloud API usa ICE-lite (RFC 8445) y siempre asume el rol controlled en ICE. Por lo tanto no hay necesidad de enviar candidatos actualizados a Meta. El agente ICE puede iniciar comprobaciones de conectividad desde direcciones no incluidas en el SDP y el agente ICE de Meta considerará una dirección desconocida como candidato válido, siempre que pase la integridad del mensaje STUN.

¿Cuál es la recomendación sobre cómo determinar el candidato ICE?

Meta tiene presencia de infraestructura global y elegirá el relay de media en la infraestructura de Meta más cercano al usuario de WhatsApp involucrado en la llamada.

En el lado del Solution Partner, el servidor/host de media (o targeting) se puede elegir según muchos parámetros, incluida la IP que elige Meta, el país del número de teléfono del consumidor y el número de teléfono del negocio. La selección de la ubicación del servidor de media es un factor importante para optimizar la latencia de media entre la IP del Solution Partner y la IP de Meta, lo que a su vez contribuye a una mayor calidad de llamada. Como mínimo, la ubicación de alojamiento de llamadas/media del Solution Partner debe estar cerca del país del usuario de WhatsApp, según el código de país del número de teléfono del usuario.

Cualquier implementación de targeting del lado del Solution Partner debe optimizar las IPs de los candidatos en los SDP de Meta, no la fuente de los endpoints de señalización.

¿Hay una API para enviar una respuesta provisional equivalente al 180 Ringing de SIP? Si no, ¿cuándo empieza a sonar el dispositivo del llamador?

El llamador (la app del consumidor de WhatsApp) ya estaría sonando para cuando se recibe el webhook. No hay necesidad de respuestas provisionales.

¿Cómo se aseguran las llamadas?

Cloud API usa SRTP para el cifrado de los flujos de media (RTP/SAVPF) y el intercambio real de claves SRTP se realiza inicialmente de extremo a extremo con DTLS-SRTP.

¿Puede Meta enviar los webhooks de llamadas a un endpoint diferente según la ubicación geográfica del llamador u otros factores como la latencia de red?

La URL del webhook es configurable. Se usa HTTPS, por lo que se pueden aplicar técnicas estándar de balanceo de carga y targeting para redirigir según corresponda. También se puede configurar una URL de webhook diferente (override o alterna) por cuenta de WhatsApp Business y por número de teléfono del negocio. El webhook solo se usa para señalización y los servidores de Meta que llaman al servidor de webhooks están ubicados en EE. UU. Selecciona la ubicación del endpoint de media según el código de país del consumidor de WhatsApp (disponible en los webhooks) o las IPs de los candidatos ICE en el SDP enviado por Meta. Consulta las preguntas "¿Cuál es la recomendación sobre cómo determinar el candidato ICE?" y "¿Cómo reducir la latencia de media de las llamadas?" más arriba.

¿Cuáles son las IPs de Meta que llamarán a los servidores Webhook, SIP o Media para poder hacer allowlist en un firewall?

Consulta la documentación de webhooks de WhatsApp sobre este tema. Al colapsar la lista de direcciones IPv4 el resultado es de alrededor de 23 prefijos. A continuación un ejemplo de comando y salida ejecutado al 11 de diciembre de 2024.

$ src % whois -h whois.radb.net — '-i origin AS32934' | grep ^route | awk '{print $2}' | grep -iv ':' | cidrmerge
31.13.24.0/21
31.13.64.0/18
45.64.40.0/22
57.141.0.0/21
57.141.8.0/22
57.141.12.0/23
57.144.0.0/14
66.220.144.0/20
69.63.176.0/20
69.171.224.0/19
74.119.76.0/22
102.132.96.0/20
103.4.96.0/22
129.134.0.0/16
147.75.208.0/20
157.240.0.0/16
163.70.128.0/17
163.77.128.0/17
173.252.64.0/18
179.60.192.0/22
185.60.216.0/22
185.89.216.0/22
204.15.20.0/22

¿Es posible reducir las IPs de Meta que llamarán a los servidores de webhooks, al menos para fines de dev-test?

No. Pero consulta la pregunta anterior, que dedujo unos 23 prefijos IPv4 para cubrir completamente todo el espacio de direcciones de Meta para v4.

¿Cuál es la política de reintentos para los webhooks relacionados con llamadas?

No asumas nada al respecto. El servidor de webhooks debe determinar los webhooks obsoletos según el valor del timestamp y evitar llamar a las Graph APIs para procesarlos más. Los webhooks de mensajería se reintentan hasta 7 días.

Es probable que los webhooks relacionados con llamadas tengan una política de reintentos más corta, pero los webhooks obsoletos aún pueden entregarse, ya que puede ser información útil para que un negocio sepa que algunos consumidores intentaron contactarlos.

¿Meta garantiza exactamente una entrega para los webhooks?

No. Prepárate para manejar webhooks duplicados.

Debido a la naturaleza distribuida de la arquitectura de Meta, no se puede garantizar la entrega exactamente una vez para ningún webhook, incluso los de mensajería. Estos son algunos escenarios conocidos donde pueden ocurrir duplicados hoy.

  1. La solicitud HTTPS de Meta al servidor de webhooks expiró después de ~20s. En este caso, el servidor piensa que manejó la solicitud correctamente, pero del lado de Meta falló por timeout. Meta reintenta enviar el webhook, lo que aparece como duplicado.
  2. Si el número de teléfono tiene más de 1 app suscrita al campo calls y Meta envía los webhooks a app1 y app2 en ese orden. Si app2 falla, Meta reintenta todo el envío, por lo que app1 recibirá un webhook duplicado. Meta está trabajando para corregir esto.
  3. La recuperación de fallos en la infraestructura de colas de Meta puede resultar en envíos duplicados de webhooks.
  4. Puede haber otras razones actualmente desconocidas.

¿Se garantiza el orden de los webhooks para una llamada determinada?

No. El orden no está garantizado debido a la naturaleza distribuida de la arquitectura de Meta y los reintentos.

Por ejemplo, el webhook terminate puede llegar antes que el webhook connect si el usuario de WhatsApp cuelga inmediatamente después de iniciar la llamada. Otros ejemplos conocidos:

El webhook connect se intenta y falla por timeout después de ~20s. El webhook terminate se envía a continuación. El reintento del webhook connect ocurre después del webhook terminate. En caso de timeout, el servidor de webhooks piensa que no hubo fallo, pero esto se ve como un fallo que amerita reintento.

¿Puedo configurar múltiples servidores de webhooks para llamadas con noción de primario/secundario para alta disponibilidad?

De forma similar a la mensajería, se pueden configurar múltiples suscripciones con apps distintas asociadas a URLs de callback distintas. Meta enviará todos los webhooks de llamadas a todas las URLs de callback configuradas. Todas las URLs se tratan por igual y no existe la noción de primario/secundario.

¿Puedo configurar URLs diferentes para los webhooks de mensajería y de llamadas?

Sí, esto se puede lograr usando 2 apps de Meta diferentes: una para mensajería y otra para llamadas.

Suscribe la app de mensajería solo a los campos de suscripción de webhooks de mensajes y la app de llamadas a los campos de suscripción de llamadas. La URL de callback se puede anular para cada una de estas apps a nivel de WABA o de número de teléfono para tener una URL override diferente para mensajes y llamadas.

Sin embargo, una sola app también puede suscribirse a ambos campos de suscripción de webhooks messages y calls. En esta configuración, la URI de callback es la misma para los webhooks de mensajes y de llamadas, pero el payload del webhook se puede usar para distinguir entre las dos categorías.

En general, se recomienda usar una sola app.

¿Puedes compartir una solicitud curl de ejemplo para interactuar con las APIs?

Consulta la sección de solicitudes cURL de muestra en la referencia de la API.

¿Cómo deben serializarse los parámetros SDP con retornos de carro y nueva línea?

El parámetro session requiere que el SDP se establezca como string según la especificación RFC-8866, que requiere CRLF para terminar un registro. El parámetro Sdp en sí es un string, por lo que no debe serializarse más. El parámetro legacy connection, en cambio, requería que el string SDP conforme a RFC-8866 estuviera dentro de una estructura JSON y, por lo tanto, requería más serialización.

En resumen, usa \r\n para el parámetro session->SDP. No uses el parámetro legacy connection->WebRTC->SDP.

¿Cómo corrijo el error ‘No fingerprint found in SDP’?

El SDP debe tener una línea a=fingerprint cuando se usa DTLS como protocolo de intercambio de claves SRTP. Asegúrate de agregar esa línea o configura el número de teléfono del negocio para usar SDES. Consulta todas las configuraciones posibles de señalización y media.

Preguntas frecuentes de WebRTC y media

¿La conexión peer to peer es de Meta al Solution Partner o al negocio final?

Normalmente es al Solution Partner, pero según la oferta de producto y la arquitectura podría ser el negocio final.

Si es el negocio final, el Solution Partner debería interactuar programáticamente con él para obtener los candidatos ICE incluidos en la llamada a la Graph API para aceptar la llamada entrante.

¿Qué sucede si la media deja de fluir desde un extremo por problemas de conexión?

Un ejemplo simple: si el endpoint de finalización de llamada falla pero el lado del negocio deja de enviar media.

Esto llevará a la falta de paquetes RTCP, que ayuda a detectar un agente WebRTC inactivo, y la llamada se desconectará seguida de un webhook de terminación.

¿El códec es siempre opus/48000?

G.711 (PCMA y PCMU) también está soportado. Para opus, la tasa de reloj RTP se establece en 48000 en el SDP según RFC 7587. Las apps móviles de WhatsApp solo soportan opus de forma nativa, por lo que la infraestructura de media de Meta transcode opus a otros códecs si es necesario.

¿Qué más está soportado en términos de códecs?

Códecs de audio soportados: OPUS, PCMA, PCMU (aka G.711).

¿Se soporta DTMF?

Sí. Consulta la sección de DTMF. La mayoría de las implementaciones SIP deberían soportar el procesamiento de DTMF proveniente del flujo de datos RTP (referencia).

¿Cuántos streams se soportan en el SDP?

Solo se soporta un stream en el SDP de Offer/Answer.

¿Cuántas tracks se soportan en cada stream del SDP?

Solo se soporta una pista de audio en el stream del SDP.

Para una llamada de consumidor a negocio, ¿pueden funcionar las apps de consumidor de WhatsApp con una oferta SDP generada por el navegador de un agente del negocio?

En este caso, el agente WebRTC dentro del navegador debe generar una respuesta SDP, no una oferta.

Esta respuesta SDP debe suministrarse a Meta mediante el endpoint de aceptación de llamada. Meta no puede trabajar con ninguna otra oferta SDP que no sea la que generó y suministró en el webhook.

¿Qué algoritmo de certificado se recomienda para DTLS?

Se recomiendan certificados ECDSA, ya que permiten una generación de certificados más rápida y handshakes DTLS más cortos debido a la falta de fragmentación.

¿Quién iniciaría las llamadas después de aceptar la llamada iniciada por el usuario: el Solution Partner o Meta?

El Solution Partner debe iniciar las comprobaciones de conectividad ICE tan pronto como decida aceptar la llamada.

Esto se puede hacer incluso antes de llamar a la API de aceptación, pero el proceso ICE solo convergerá después de que Meta procese la respuesta SDP, debido a la necesidad del fingerprint del certificado DTLS.

¿Cuáles son los números de puerto usados por los candidatos ICE en el SDP de Meta para el allowlisting en firewalls?

Los números de puerto pueden ser cualquiera de: 40012, 3482, 3484, 3478, 3480. Están sujetos a cambios.

¿Cómo puedo generar el SDP de aceptación WebRTC?

Consulta la documentación de la librería o herramienta WebRTC que planees usar.

Procesar una oferta SDP para generar una respuesta SDP es la funcionalidad principal de cualquier stack de tecnología VoIP.

¿Cómo reducir la latencia de media de las llamadas?

Los algoritmos de targeting de Meta elegirán el relay de Meta que recibe media del Solution Partner cerca de la ubicación del consumidor de WhatsApp. Este relay de media es el candidato ICE que Meta compartirá en el SDP. Cualquier targeting del lado del Solution Partner debe colocar los servidores de media del Solution Partner en la misma región que el consumidor. Esto minimiza obviamente la latencia para llamadas dentro de la misma región, y minimiza las rutas de paquetes de media en la internet pública para llamadas internacionales.

¿Hay un proceso de reconexión si hay una caída temporal de red en cualquiera de los extremos del tramo de media?

Las apps de consumidor de WhatsApp intentarán una reconexión y recuperarán automáticamente ese tramo de la llamada una vez restaurada la conectividad de red.

Para el tramo del negocio, se esperan condiciones de red relativamente más estables. Actualmente no hay soporte para re-handshake o re-negociación de SDP. En cualquier caso, la llamada puede terminar después de un cierto período de inactividad, tras lo cual se envía un webhook de terminación.

¿Cuánto ancho de banda se requiere para que el centro de llamadas soporte un número determinado de llamadas concurrentes?

Por llamada, se necesitan aproximadamente 40 kbps para el códec + 20 kbps de overhead.

El códec Opus tiene la capacidad de cambiar dinámicamente el ancho de banda consumido según las condiciones de la red. En general puede ofrecer mejor calidad de audio con menor consumo de ancho de banda, comparado con el códec G711.

El códec G711 en comparación necesita 64 kbps para el códec + 20 kbps de overhead = 84 kbps por llamada.

Multiplica los números anteriores por el número esperado de llamadas concurrentes para calcular el ancho de banda acumulado requerido. Ejemplo: un ancho de banda de 1mbps puede manejar aproximadamente 15 llamadas concurrentes en opus (1000/64) vs. 12 llamadas concurrentes en G711 (1000/84).

Para calcular el uso total de datos, multiplica el ancho de banda por la duración de la llamada en segundos. Para Opus es un poco más complejo porque tiene ancho de banda variable según muchos factores, incluido el ancho de banda disponible estimado mediante estimación de ancho de banda, si la parte local habla o está en silencio, etc. Pero aproximadamente, una llamada de 1 min en Opus consume 3.75MB de datos vs. la misma en G711 que consume 4.9MB.

¿Es posible transferir una llamada de un agente a otro durante una sesión de llamada activa? En esencia, ¿un cliente hablando con el Agente A necesita ser transferido al Agente B?

Meta no tiene soporte nativo.

Meta desconoce los diferentes agentes del lado del negocio/partner, por lo que la transferencia de llamadas es una operación que se puede realizar únicamente del lado del partner. Por ejemplo, el flujo de media puede ser servidor de media de Meta a servidor de media del Partner al Agente A. Cuando ocurre la transferencia, el flujo pasa a ser servidor de media de Meta a servidor de media del Partner al Agente B. En ambos casos, el tramo del servidor de media de Meta al servidor de media del Partner permanece constante.

Preguntas frecuentes del cliente de WhatsApp

¿Cuándo es visible el ícono de llamada en la barra de título del chat en las apps de consumidor de WhatsApp?

Es visible cuando se cumplen todas las siguientes condiciones:

  • El número de teléfono del negocio tiene el estado de llamadas configurado en ENABLED en la Call Settings API.
  • El call_icon_visibility del número de teléfono del negocio no es HIDE_IN_CHAT ni DISABLE_ALL.
  • La función de visibilidad del ícono de llamada está soportada en versiones de WhatsApp mobile 2.24.10.8 y superiores en Android e iOS.
  • La versión de WhatsApp del consumidor es 2.23.14 o superior. Se espera que todos los consumidores estén en esta versión o superior.

Consulta la Call Settings API para aprender más.

¿Por qué el ícono de llamada en la app de consumidor de WhatsApp no refleja la configuración de llamadas actual?

Después de actualizar la configuración de llamadas, los usuarios de WhatsApp pueden tardar hasta 7 días en reflejar esa configuración, aunque la mayoría refresca mucho antes. Se puede forzar un refresco inmediato entrando a la ventana de chat con el negocio y abriendo la página de información del chat. Independientemente del comportamiento del cliente de WhatsApp, la semántica de la configuración se respeta en el lado del servidor.

Para solucionar el ícono de llamada que no aparece, sigue estos pasos:

  • Navega a la ventana de chat del negocio y haz clic en el nombre o número del negocio en la barra de título del chat. Esto abre la pantalla de Información del negocio y fuerza a la app a refrescar el estado de llamadas del negocio.
  • Sal de la ventana de chat del negocio y vuelve a entrar.
  • Si el estado esperado aún no es visible, cierra la app de WhatsApp y reiníciala.
  • Asegúrate de obtener los ajustes de llamadas para confirmar los ajustes esperados.

¿Cuánto tiempo tarda el cliente de WhatsApp en reflejar los cambios en la configuración de llamadas?

Puede tardar hasta 7 días, aunque la mayoría de los usuarios de WhatsApp deberían reflejar los cambios mucho antes.

Una cuenta de WhatsApp Business puede tener chats con cualquier cantidad de más de 3000 millones de usuarios de WhatsApp. Las actualizaciones de la configuración de llamadas envían notificaciones de cambio a todos los usuarios que tienen un chat con este negocio visible en su bandeja de entrada de WhatsApp. Sin embargo, la entrega de notificaciones es best effort, por lo que no todos los usuarios pueden recibirla.

Todos los clientes de WhatsApp refrescan la información del negocio (incluida la configuración de llamadas) cada 7 días, independientemente de recibir notificaciones de cambio.

En cualquier caso (impulsado por notificación o refresco de 7 días), una vez que se refresca el estado local en el cliente de WhatsApp, se refleja en la UI solo en la siguiente entrada a la pantalla de chat o de información del chat.

¿Debo crear una allowlist de números de consumidores para que funcionen las llamadas?

No.

¿Es posible limitar el acceso a llamadas a usuarios específicos o individuales de WhatsApp en lugar de a todos?

Ejemplo: un lead calificado o un cliente en tier premium.

No. No hay forma de controlar la visibilidad o el acceso de llamadas de forma individual por usuario de WhatsApp. Sin embargo, la Call Settings API se puede usar para configurar call_icon_visibility en DISABLE_ALL, lo que ocultará los íconos de llamada a todos los usuarios de WhatsApp. Para los usuarios calificados, se puede enviar un mensaje con el botón CTA de llamada para que solo ellos puedan llamar al negocio tocando el botón del mensaje.

Proporcionar este tipo de función requeriría que Meta almacene configuración por usuario de WhatsApp, lo que conlleva mayor riesgo de privacidad. También generaría mayor overhead operativo para mantener grandes listas de usuarios de WhatsApp en allowlist de forma continua.

Cuando el ícono de llamada está oculto con la Call Settings API, ¿aún pueden llamar los consumidores al negocio?

Sí.

Un usuario aún puede llamar al negocio desde otros puntos de entrada que no se ven afectados por la Call Settings API, como:

  • Guardar el número del negocio como contacto y usar nueva llamada.
  • Registros de llamadas de la pestaña Llamadas > Recientes.
  • CTA de llamada en mensajes enviados por el negocio.
  • Burbuja de llamada en la ventana de chat que aparece después de cualquier llamada entre el usuario y el negocio.

Por lo tanto, la recomendación es tratar DISABLE_ALL solo como un filtro amplio de primer nivel y asegurarse de que los webhooks hagan cualquier filtrado adicional según la lógica de negocio específica.

¿Cómo escribirán dígitos los consumidores de WhatsApp para DTMF?

Las apps de consumidor de WhatsApp se extienden para soportar un nuevo teclado para llamadas de negocios.

Aprende más sobre el soporte DTMF en la Calling API.

¿Cuál es la versión mínima de las apps móviles de WhatsApp que soportan el botón de llamada de voz?

  • La versión mínima de app para Android es 2.24.1.

¿Cuál es la experiencia en el lado del consumidor de WhatsApp en varios puntos del flujo de configuración de llamada?

Cuando un consumidor de WhatsApp llama a un negocio, el tono local de ringback comienza inmediatamente si el dispositivo del consumidor tiene conectividad a internet.

La UI de llamada muestra ‘Calling BUSINESS_NAME’. Cuando Cloud API recibe la solicitud de llamada del consumidor y pre-acepta la llamada, la UI de llamada cambia a ‘Ringing BUSINESS_NAME’. Después de la llamada a la Graph API de aceptación, la UI de llamada cambia a una ventana de llamada activa que muestra el temporizador en vivo de la duración de la llamada.

¿Se soportan llamadas para usuarios finales desde WhatsApp Web o WhatsApp Desktop?

No. WhatsApp Web no soporta llamadas de consumidor a consumidor ni de negocio. Las apps de escritorio solo soportan llamadas de consumidor a consumidor por ahora.

Preguntas frecuentes de llamadas iniciadas por el negocio

¿Qué versiones de WhatsApp y plataformas cliente soportan la función de llamadas iniciadas por el negocio?

Las versiones de cliente de WhatsApp 2.24.14.x y posteriores soportan las solicitudes de permiso de llamada y la función de llamadas iniciadas por el negocio.

Tanto las plataformas Android como iOS de WhatsApp soportan la función.

¿Cómo evitar 138011 en conversaciones iniciadas por el negocio y por el usuario durante el desarrollo, integración y pruebas?

Conversación iniciada por el usuario:

  • Envía un mensaje al número de Cloud API desde la cuenta de consumidor de WhatsApp.
  • Envía cualquier mensaje aparte del mensaje de permiso de llamada al usuario.
  • Envía una solicitud de permiso de llamada al usuario.
  • Acepta la solicitud de permiso de llamada en el dispositivo del usuario.

Conversación iniciada por el negocio:

  • Envía un mensaje de plantilla al usuario desde el negocio.
  • Envía la solicitud de permiso de llamada al usuario.
  • Acepta la solicitud de permiso de llamada en el dispositivo del usuario.

¿Hay una forma de reiniciar los límites de solicitud de permiso de llamada?

Una llamada conectada reiniciará los límites de permiso de llamada.

¿Qué sucede si el usuario de WhatsApp ha configurado los ajustes de Silence Unknown Callers?

Las llamadas iniciadas por el negocio omiten los ajustes de ‘Silence Unknown Callers’ ya que la llamada solo puede ocurrir después del permiso explícito del usuario.

¿Por qué mi mensaje de solicitud de permiso de llamada se renderiza diferente?

WhatsApp renderiza los mensajes en versiones de app cliente no soportadas de forma diferente a las soportadas.

Después de que el usuario de WhatsApp actualice su app cliente, se renderizará correctamente.

Recibí el error 138001 después de enviar una solicitud de permiso de llamada, ¿qué hago?

Consulta los códigos de error en la página de troubleshooting.

¿El permiso expira después de alcanzar el límite de llamadas conectadas de 24 horas? Estoy viendo el error 138012.

El límite de llamadas conectadas en 24 horas es un límite continuo basado en ventana de tiempo. Alcanzar ese límite no revoca el permiso; el permiso permanece abierto hasta los 7 días completos para los permisos temporales o de forma permanente para los permisos siempre permitidos. La Call Permissions API proporciona el timestamp exacto de cuándo expira este límite y se puede realizar la próxima llamada.

Piénsalo como un límite de velocidad para las llamadas iniciadas por el negocio.

Preguntas frecuentes de SIP

Consulta Errores SIP para errores específicos de SIP y sus posibles soluciones.

¿Por qué la llamada iniciada por el usuario se desconecta inmediatamente después de habilitar SIP?

La razón más probable es un error de validación de certificado: consulta Cómo probar si tienes un certificado TLS válido.

¿Por qué no recibo solicitudes SIP (INVITE, BYE, etc.) cuando lo espero?

Si no recibes el SIP INVITE después de una llamada iniciada por el usuario o un SIP BYE después de la terminación de una llamada iniciada por el usuario, las razones posibles incluyen:

  • Error de validación del certificado TLS: consulta Cómo probar si tienes un certificado TLS válido.
  • SIP no está configurado. Obtén la configuración de llamadas para asegurarte de que SIP está habilitado.
  • La app que configuró el servidor SIP no tiene el permiso whatsapp_business_messaging en el número de teléfono del negocio. Intenta enviar un mensaje usando el mismo número de teléfono del negocio como forma de verificar que los permisos correctos están en su lugar.
  • Problema de conectividad de red: tu servidor SIP puede no ser alcanzable desde Meta en el puerto que configuraste para SIP. Puedes verificar la conectividad TCP básica a tu servidor SIP ejecutando el siguiente comando:
nc -zvw2 -G 2 <your-sip-server> <your-sip-port>

Reemplaza <your-sip-server> con el hostname de tu servidor SIP y <your-sip-port> con el puerto configurado en tu servidor SIP.

Ejemplo: falla (connection timed out)

$ nc -zvw2 -G 2 your-sip-server.example.com 5061
nc: connectx to your-sip-server.example.com port 5061 (tcp) failed: Operation timed out

Ejemplo: éxito (el puerto es alcanzable)

$ nc -zvw2 -G 2 your-sip-server.example.com 5061
Connection to your-sip-server.example.com port 5061 [tcp/sip-tls] succeeded!

Si la conexión expira o es rechazada, revisa las reglas de tu firewall y asegúrate de que el puerto configurado esté abierto y que tu servidor SIP esté escuchando en él. También verifica que las IPs de Meta estén en allowlist en tu firewall.

¿Por qué Meta aparentemente no envía un ACK para nuestra respuesta 200 OK?

La razón más probable es que tu 200 OK modifica incorrectamente los encabezados record-route de Meta en la solicitud SIP INVITE de Meta.

Consulta el ejemplo de Asterisk en patrones de integración para ver los detalles completos y la solución a este problema.

Este problema se manifiesta como una llamada iniciada por el usuario que se conecta, con flujo de audio bidireccional, pero el usuario deja de escuchar el audio del negocio alrededor de los ~33 segundos debido a que tu servidor SIP agota el tiempo del diálogo SIP.

¿Por qué nuestro SIP TERMINATE a Meta no cuelga la llamada en el lado del usuario de WhatsApp?

La razón común es un fallo de handshake TLS cuando el servidor SIP intenta establecer una sesión TLS con el servidor SIP de Meta. Haz una captura de paquetes de red del tráfico SIP o revisa los logs del servidor SIP para confirmar el handshake TLS exitoso.

¿Por qué mi servidor SIP responde continuamente con 401 Unauthorized para llamadas iniciadas por el usuario?

Meta soporta autenticación digest SIP para llamadas iniciadas por el usuario. Cuando el servidor SIP responde con 401 Unauthorized (consulta el flujo de ejemplo), el servidor SIP de Meta reenviará el INVITE con el encabezado Authorization correcto. Asegúrate de que el servidor SIP esté configurado con el username como el número de teléfono del negocio y la password como la password generada por Meta para el número de teléfono del negocio.

Alternativamente, la autenticación digest se puede deshabilitar en el servidor SIP, aunque esto NO se recomienda desde el punto de vista de las mejores prácticas de seguridad.

¿Por qué mi servidor SIP responde con 488 Not Acceptable Here?

Consulta la documentación del servidor SIP o al proveedor. La razón probable es que el servidor SIP no soporta el protocolo WebRTC ICE (Interactive Connectivity Establishment). Para corregirlo, configura el número de teléfono del negocio para usar SDES.

¿Es necesario hacer SIP REGISTER del número de teléfono del negocio al servidor SIP de Meta?

No. No envíes solicitudes REGISTER al servidor SIP de Meta. Hacerlo es un consumo de recursos innecesario en ambos lados. Las solicitudes REGISTER fallarán con el error 403 Forbidden. El servidor SIP de Meta solo posee el dominio meta.vc y los únicos usuarios SIP en ese dominio son usuarios regulares de consumidor de WhatsApp. Los números de WhatsApp Business pertenecen al dominio SIP configurado usando la settings API.

¿Meta soporta re-INVITEs SIP?

No. Los re-INVITEs no están soportados hoy. El servidor SIP de Meta devuelve un 500 Internal Server Error.

¿SIP calling es tan bueno como la opción de Cloud Graph API/webhook? ¿Hay alguna razón para elegir uno sobre el otro?

Sí, hay paridad funcional entre las dos opciones. La mejor forma de identificar la mejor opción es completar una evaluación exhaustiva y seleccionar según las necesidades.

¿Si se usa SIP para llamadas, aún se necesitan webhooks?

SIP para llamadas solo cubre eventos específicos de llamadas. Para mensajería o cualquier evento no relacionado con llamadas, los webhooks aún deben usarse.

¿Meta reutiliza conexiones TLS para múltiples mensajes SIP dentro de la misma llamada?

No dependas de la reutilización de conexiones TLS para solicitudes SIP iniciadas por Meta (mensajes mid-dialog como BYE). Sin embargo, Meta sí impone la reutilización de conexiones TLS para las respuestas SIP, que siempre se envían de vuelta en la misma conexión en la que llegó la solicitud.

Si una solicitud iniciada por Meta reutiliza una conexión TLS existente o abre una nueva depende del routing interno de Meta en ese momento. A volúmenes de llamadas más altos, es más probable que se reutilicen las conexiones TLS.

¿Meta tiene una lista específica y aprobada de proveedores o SBCs para SIP?

No. Cualquier servidor SIP compatible.