Webhooks
Entregas de eventos firmadas: eventos disponibles, verificación de X-LinkProfit-Signature en JavaScript y Python, reintentos y estado de fallo.
Actualizado el 13 de agosto de 2026
Los webhooks envían eventos a tu endpoint como solicitudes POST en JSON, sin
sondeo. Registra endpoints en el panel (Ajustes → Webhooks) o mediante
POST /v1/webhooks; el secreto de firma se muestra una sola vez al crearlo.
Eventos
| Evento | Se dispara cuando | Disponible para |
|---|---|---|
| link.created / link.updated / link.deleted | Cambia un enlace, desde el panel, la API o una importación masiva | endpoints de espacio de trabajo y de partner |
| domain.pending_ssl | El DNS está verificado y se está emitiendo el certificado | espacio de trabajo y partner |
| domain.activated | El dominio ya sirve tráfico | espacio de trabajo y partner |
| domain.error | Falló el aprovisionamiento; los detalles van dentro | espacio de trabajo y partner |
| click.threshold | Se alcanza el 80% / 100% del límite mensual de clics medidos | espacio de trabajo y partner |
| conversion.created | Se registra una conversión: un pedido, un registro o un objetivo personalizado atribuido a un clic | espacio de trabajo y partner |
| workspace.subscribed | Un cliente paga la primera factura de una suscripción | solo partner |
| workspace.past_due | Falla el pago de un cliente | solo partner |
| workspace.suspended | Se suspende a un cliente (por impago o manualmente) | solo partner |
| payment.succeeded | Se liquida el pago de un cliente, con el desglose de comisiones | solo partner |
| payment.refunded | Se reembolsa un pago | solo partner |
La entrega
POST /your/endpoint HTTP/1.1
Content-Type: application/json
X-LinkProfit-Event: link.created
X-LinkProfit-Delivery: dlv_8Yq2…
X-LinkProfit-Signature: t=1755081600,v1=5f8a2c…
{
"id": "dlv_8Yq2…",
"type": "link.created",
"created_at": "2026-08-13T10:00:00.000Z",
"data": { "id": "lnk_…", "domain": "go.your-brand.com", "slug": "x7f2q1z", "url": "https://example.com" }
}
Responde con cualquier 2xx en menos de 10 segundos. Cualquier otra cosa —un
tiempo de espera agotado incluido— cuenta como fallo y programa un reintento.
Las entregas pueden llegar desordenadas y, rara vez, dos veces: deduplica por
id.
Verificar la firma
La firma es un HMAC-SHA256 sobre `${t}.${rawBody}` con el secreto de tu
endpoint, codificado en hexadecimal. Verifica siempre contra el cuerpo en
bruto de la solicitud, antes de cualquier análisis de JSON, y rechaza las
marcas de tiempo de más de 5 minutos.
import { createHmac, timingSafeEqual } from "node:crypto";
function verifySignature(secret, rawBody, header, toleranceSeconds = 300) {
const parts = Object.fromEntries(
header.split(",").map((piece) => piece.split("=", 2)),
);
if (!parts.t || !parts.v1) return false;
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > toleranceSeconds) return false;
const expected = createHmac("sha256", secret)
.update(`${parts.t}.${rawBody}`)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(parts.v1);
return a.length === b.length && timingSafeEqual(a, b);
}
import hashlib
import hmac
import time
def verify_signature(secret: str, raw_body: bytes, header: str, tolerance: int = 300) -> bool:
parts = dict(piece.split("=", 1) for piece in header.split(",") if "=" in piece)
timestamp, signature = parts.get("t"), parts.get("v1")
if not timestamp or not signature:
return False
if abs(time.time() - int(timestamp)) > tolerance:
return False
expected = hmac.new(
secret.encode(), f"{timestamp}.".encode() + raw_body, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
Reintentos y estado de fallo
El primer intento es inmediato. Los fallos se reintentan con un calendario
fijo: 1 min → 5 min → 30 min → 2 h → 12 h. Tras el quinto reintento, el
endpoint se marca como failing, deja de recibir eventos nuevos y su
propietario recibe un correo.
Arregla el endpoint y vuelve a activarlo desde el panel o con
PATCH /v1/webhooks/{id} y {"status": "active"}. Los eventos perdidos no se
reenvían automáticamente: el registro de entregas
(GET /v1/webhooks/{id}/deliveries o el panel) muestra todos los payloads para
que puedas conciliar.
Una entrega correcta pone a cero la racha de fallos.
Pruebas
El botón Enviar prueba (o POST /v1/webhooks/{id}/test) entrega un evento
real y firmado con "data": { "test": true } por la misma tubería que los
eventos de producción, y el registro de entregas muestra la respuesta de tu
endpoint.