Tu URL de webhook es pública, así que cualquiera podría mandarle un POST. Para que sepas que el aviso es de eltick, cada uno viene firmado con el secreto de firma (whsec_…) que te mostramos al crear el webhook.

Cómo es la firma

El encabezado X-Eltick-Signature tiene dos partes separadas por coma:
  • t: el momento de la firma, en segundos Unix.
  • v1: el HMAC-SHA256, en hexadecimal, de este texto: el valor de t, un punto y el cuerpo crudo del pedido.

Cómo verificarla

1

Lee el cuerpo crudo

Usa los bytes tal como llegaron, antes de convertirlos a JSON. Si parseas y vuelves a serializar, cambian los espacios o el orden y la firma no coincide.
2

Separa t y v1

Divide el encabezado por , y cada parte por el primer =.
3

Calcula tu propia firma

HMAC-SHA256 con tu secreto sobre t + "." + cuerpo, en hexadecimal.
4

Compara en tiempo constante

Usa timingSafeEqual, hmac.compare_digest o hash_equals, no ==. Así nadie puede adivinar la firma midiendo cuánto tarda tu servidor.
5

Revisa que sea reciente

Rechaza firmas con t de hace más de 5 minutos. Así, si alguien captura un aviso, no puede reenviártelo más tarde.

Ejemplos

Prueba tu código

Con estos datos, tu función tiene que devolver true (desactiva por un momento el control de los 5 minutos, porque la fecha es fija): También puedes calcular la firma desde la terminal:
Y la forma más fácil de probar con un aviso real es el botón Probar de Ajustes › API y webhooks.

Si la firma no coincide

Es la causa más común. Frameworks como Express (express.json()), NestJS o Laravel parsean el JSON antes de que lo veas. Configura la ruta del webhook para recibir el cuerpo crudo.
Cada webhook tiene su propio secreto. Si tienes varios, usa el que corresponde a esa URL.
No se puede volver a ver. Crea un webhook nuevo con la misma URL y los mismos eventos, actualiza el secreto en tu servidor y elimina el anterior.
Revisa que el reloj de tu servidor esté sincronizado (NTP). Un reloj atrasado unos minutos hace que todas las firmas parezcan viejas.