Skip to main content
Cada solicitud que enviamos a tu servidor —entregas de webhooks e invocaciones de endpoints de herramientas— incluye una firma HMAC-SHA256 en el encabezado X-ThunderPhone-Signature. Implementa la verificación correctamente una vez y reutiliza el mismo helper en cada controlador.

El algoritmo

  1. Lee el cuerpo sin procesar de la solicitud: los bytes exactos que te enviamos mediante POST.
  2. Calcula hmac_sha256(secret, body).hexdigest().
  3. Compara en tiempo constante con X-ThunderPhone-Signature. (Una comparación de cadenas ingenua filtra información de temporización).
Firmamos exactamente los bytes que transmitimos, por lo que verificar el cuerpo sin procesar siempre funciona. Esos bytes también son la serialización JSON canónica de la carga útil: claves ordenadas alfabéticamente, separadores compactos (, y : sin espacios), UTF-8. Esto te ofrece una segunda receta totalmente equivalente cuando tu framework solo expone JSON analizado: vuelve a serializar canónicamente y calcula el HMAC de eso.
Prefiere el cuerpo sin procesar: es un paso menos y evita peculiaridades de conversión de números JSON de ida y vuelta en algunos lenguajes.

¿Qué secreto?

Almacena el secreto en tu administrador de secretos o variable de entorno; nunca lo confirmes en el repositorio.

Implementaciones de referencia

Las cuatro verifican el cuerpo sin procesar de la solicitud:

Integración específica del framework

Verificación de llamadas a herramientas

Cuando el agente invoca directamente una de tus herramientas de función (la herramienta tiene un endpoint), la solicitud incluye dos encabezados de ThunderPhone junto con tus endpoint.headers configurados:
  • X-ThunderPhone-Call-ID — el ID numérico de la llamada activa.
  • X-ThunderPhone-Signature — HMAC-SHA256, con clave de tu secreto de webhook a nivel de organización, sobre los bytes exactos del cuerpo de la solicitud.
El mismo helper verify() funciona sin cambios, con dos particularidades:
  1. Las herramientas GET / DELETE no tienen cuerpo. Los argumentos se envían como parámetros de consulta y la firma se calcula sobre la cadena de bytes vacía; es decir, verify(b"", sig, secret) (Python) o verify(Buffer.alloc(0), sig, secret) (Node). No calcules el hash de la cadena de consulta.
  2. Las organizaciones sin un webhook heredado configurado no tienen secreto de organización. En ese caso, las llamadas a herramientas incluyen solo X-ThunderPhone-Call-ID y ningún encabezado de firma. Configura el webhook heredado (PUT /v1/webhook) para obtener un secreto de firma, o autentica las llamadas a herramientas con tu propio encabezado mediante endpoint.headers.
El despacho de herramientas en modo webhook (herramientas sin un endpoint, enviadas a tu webhook de organización como telephony.tool / web.tool) es un webhook firmado común: se aplica la receta estándar anterior. Consulta Herramientas de función para ambas formas de solicitud.

Errores comunes

Analizar el cuerpo y volver a serializarlo con los valores predeterminados de tu biblioteca JSON (espacios después de , / :, claves en orden de inserción) produce bytes diferentes y rompe el HMAC. Verifica el cuerpo sin procesar; o, si debes reserializarlo, coincide exactamente con nuestra forma canónica: claves ordenadas, separadores compactos, UTF-8.
El middleware express.json() de Express consume el flujo del cuerpo y pierdes los bytes sin procesar. Usa express.raw() específicamente en la ruta del webhook, o almacena el cuerpo sin procesar en un middleware previo. Lo mismo ocurre con NestJS / Koa: consulta su documentación sobre “raw body”.
expected === signature en JS o expected == signature en Python son comparaciones con tiempo variable. Usa crypto.timingSafeEqual o hmac.compare_digest, respectivamente. La diferencia de rendimiento es nula.
Las llamadas directas a endpoints de herramientas se firman con el secreto de webhook a nivel de organización (GET /v1/webhook), no con ningún secreto por endpoint de /v1/developer/webhook-endpoints. Reutiliza la misma función verify(), pero asegúrate de proporcionarle el secreto de la organización en las rutas de herramientas.
Para los métodos de herramientas sin cuerpo, la firma cubre la cadena de bytes vacía, manteniendo una única receta universal: aplica HMAC al cuerpo sin procesar de la solicitud, sea cual sea. Hashear la URL o la cadena de consulta nunca coincidirá.
Devolver 200 cuando falla la verificación convierte el controlador en un objetivo de repetición. Responde siempre con un código distinto de 2xx si la verificación falla.

Próximos pasos

Descripción general de webhooks

Semántica de entrega, reintentos e IP de origen.

Endpoints de webhook

Administra varias URL y rota secretos.

Herramientas de función

Las dos rutas de invocación de herramientas y las formas de sus solicitudes.

Integraciones de herramientas

Crea una integración completa respaldada por herramientas de principio a fin.