Ir al contenido

Webhooks

Los webhooks permiten que Semantico avise a tus sistemas en el momento en que termina una tarea de generación de producto, sin que tengas que consultar periódicamente. Semantico admite una configuración de webhook por espacio de trabajo.

Gestiona tu webhook mediante los endpoints de configuración:

  • GET /settings/webhooks/: obtiene la configuración actual.
  • POST /settings/webhooks/: crea o sustituye la configuración (un POST siempre sustituye la única configuración existente).
  • DELETE /settings/webhooks/: la elimina.

Cuerpo de la petición:

{
"url": "https://example.com/webhook",
"hmac_secret": "your-shared-secret",
"actions": ["product_generated", "product_generation_failed", "product_generation_no_urls"]
}
  • url (obligatorio): dirección a la que se envían las entregas.
  • hmac_secret (opcional): si se define, cada entrega se firma para que puedas verificar que procede de Semantico.
  • actions (opcional): qué eventos se entregan. Si se omite, se activan todos los eventos.

Eventos disponibles:

Evento Se dispara cuando
product_generated Un producto ha terminado de generarse correctamente.
product_generation_failed La generación de un producto ha fallado.
product_generation_no_urls No se ha encontrado ninguna URL de origen para el producto.
  • Las entregas son peticiones POST con Content-Type: application/json.
  • El tiempo de espera es de 10 segundos.
  • Las entregas fallidas se reintentan hasta 5 veces con espera progresiva (aproximadamente a los 1 s, 8 s, 60 s, 120 s y 420 s). Un 2xx se considera un éxito; un 4xx se considera un error permanente y no se reintenta; el resto de respuestas (5xx, tiempos de espera agotados, errores de conexión) se reintentan.
  • Semantico no te avisará dos veces por la misma combinación de producto y evento.

Cada entrega contiene:

  • action: el nombre del evento.
  • status: el estado de la tarea.
  • reason_for_failure: un motivo de fallo opcional.
  • credits: créditos consumidos (consumed) y restantes (remaining).
  • task: metadatos de la tarea (id, marcas de tiempo, URLs de origen).
  • product: el payload completo del producto (o null si no está disponible). Los atributos personalizados se devuelven en la clave sections.
{
"action": "product_generated",
"status": "SUCCESS",
"reason_for_failure": "",
"credits": { "consumed": 10, "remaining": 1230 },
"task": {
"id": "b3b8c9c8-4a62-4b59-9caa-7d7b1f5a1234",
"status": "SUCCESS",
"created_at": "2026-02-09T10:00:00Z",
"updated_at": "2026-02-09T10:01:00Z",
"urls": [
{
"id": 1,
"url": "https://example.com/product",
"status": "SUCCESS",
"relevant_score": 0.95,
"is_user_provided_link": true
}
]
},
"product": {
"id": 123,
"sku": "MODEL-001",
"is_product_model": true
}
}

Si defines un hmac_secret, cada entrega incluye dos cabeceras:

  • X-Webhook-Timestamp: marca de tiempo Unix (en segundos) de la entrega.
  • X-Webhook-Signature: sha256=<hex>, un HMAC-SHA256 del payload firmado.

El payload firmado es la marca de tiempo y el cuerpo sin procesar de la petición unidos por un punto:

signed_payload = "<X-Webhook-Timestamp>" + "." + "<raw JSON request body>"
signature = "sha256=" + HMAC_SHA256(secret, signed_payload) // hex digest

Para verificarla, vuelve a calcular la firma sobre el cuerpo sin procesar que has recibido y compárala con X-Webhook-Signature. Si no hay ningún hmac_secret configurado, estas cabeceras no se envían.

Verificación en Python:

import hashlib
import hmac
def is_valid(secret: str, timestamp: str, raw_body: bytes, signature: str) -> bool:
signed = f"{timestamp}.".encode() + raw_body
expected = "sha256=" + hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature)