Webhooks
TryYourSize envía eventos a los endpoints (puntos de conexión) HTTPS que añadas en Studio → Desarrolladores → Webhooks (Developers → Webhooks). Cada endpoint pertenece a una tienda y a un modo (de prueba o real); hasta 16 por tienda. Cada endpoint se suscribe a una lista de tipos de evento, o a todos (*). Su secreto de firma (whsec_…) se muestra una sola vez.
Tipos de evento
Sección titulada «Tipos de evento»Los payloads nunca incluyen la identidad ni las medidas de quien compra.
| Tipo | data |
Cuándo |
|---|---|---|
fit.recommended |
tryon_id, product_sku, recommended_size, no_size_fits |
Una vez por resultado de tallaje, tienda y modo |
garment.published |
garment_version_id, fit_group_id, version, product_skus |
Se publicó una versión de una prenda (se envía a los endpoints de prueba y reales) |
fit_check.completed |
fit_check_id, garment_version_id, status |
Una prueba de tallaje de Studio terminó o falló |
profile.disconnected |
connection_id, reason |
Una persona compradora desconectó tu tienda (solo en modo real) |
usage.threshold_reached |
Próximamente: tu uso alcanzó un umbral de tu plan | |
webhook.test |
“Enviar evento de prueba” (Send test event) en Studio |
El sobre
Sección titulada «El sobre»{ "id": "evt_…", "object": "event", "type": "fit.recommended", "api_version": "2026-10", "created": 1793000000, "mode": "live", "store_id": "…", "data": { "tryon_id": "…", "product_sku": "CREW-TSHIRT", "recommended_size": "M", "no_size_fits": false }}Cabeceras: TYS-Signature, TYS-Event-Id, TYS-Event-Type, TYS-Delivery-Id, TYS-Delivery-Attempt. El mismo evento puede llegar más de una vez: elimina duplicados con TYS-Event-Id (el id del sobre).
Verifica la firma
Sección titulada «Verifica la firma»TYS-Signature: t=1793000000,v1=5f2c…v1 es el HMAC-SHA256 en hexadecimal de "<t>.<cuerpo bruto de la petición>", con el secreto whsec_… completo como clave. Mientras rotas un secreto, hay dos valores v1 (uno por secreto) durante 24 horas: acepta la petición si alguno coincide. Rechaza las marcas de tiempo de hace más de 5 minutos. Verifica siempre el cuerpo bruto, antes de cualquier parseo JSON.
import express from "express";import TryYourSize from "@tryyoursize/node";
const tys = new TryYourSize(process.env.TYS_SECRET_KEY!);const app = express();
app.post("/webhooks/tryyoursize", express.raw({ type: "application/json" }), (req, res) => { let event; try { event = tys.webhooks.constructEvent(req.body, req.header("TYS-Signature")!, process.env.TYS_WEBHOOK_SECRET!); } catch { return res.sendStatus(400); } if (event.type === "garment.published") { /* … */ } res.sendStatus(200);});import osimport tryyoursizefrom flask import Flask, request
app = Flask(__name__)
@app.post("/webhooks/tryyoursize")def webhook(): try: event = tryyoursize.Webhook.construct_event( request.get_data(), request.headers["TYS-Signature"], os.environ["TYS_WEBHOOK_SECRET"] ) except Exception: return "", 400 if event["type"] == "garment.published": ... return "", 200import { createHmac, timingSafeEqual } from "node:crypto";
export function verify(rawBody: Buffer, header: string, secret: string, toleranceSec = 300): boolean { const parts = header.split(",").map((p) => p.split("=")); const t = parts.find(([k]) => k === "t")?.[1]; const sigs = parts.filter(([k]) => k === "v1").map(([, v]) => v); if (!t || !sigs.length) return false; if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSec) return false; const expected = createHmac("sha256", secret).update(`${t}.`).update(rawBody).digest(); return sigs.some((s) => { const got = Buffer.from(s, "hex"); return got.length === expected.length && timingSafeEqual(got, expected); });}import hashlib, hmac, time
def verify(raw_body: bytes, header: str, secret: str, tolerance: int = 300) -> bool: items = [p.split("=", 1) for p in header.split(",") if "=" in p] t = next((v for k, v in items if k == "t"), None) sigs = [v for k, v in items if k == "v1"] if t is None or not sigs or abs(time.time() - int(t)) > tolerance: return False expected = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest() return any(hmac.compare_digest(expected, s) for s in sigs)En cualquier otro lenguaje: divide la cabecera por ,, toma t y cada v1, calcula el HMAC-SHA256 de t + "." + cuerpo bruto con el secreto como clave, codifícalo en hexadecimal, compáralo en tiempo constante con cada v1 y comprueba que t esté a menos de 5 minutos de la hora actual.
Respuestas y reintentos
Sección titulada «Respuestas y reintentos»- Responde con cualquier 2xx en menos de 10 segundos para confirmar la recepción. Haz el trabajo lento después de responder.
- No se siguen las redirecciones; el cuerpo de la respuesta se ignora.
- Ante otro código de estado, un timeout o un error de red, reintentamos: un intento inmediato y luego a los 1 min, 5 min, 30 min, 2 h, 5 h y 10 h, y después cada 12 h: 12 intentos en unas 72 horas.
- Responde 410 Gone para detener los reintentos de esa entrega.
- Desactivar o eliminar el endpoint detiene las entregas pendientes.
Studio muestra cada entrega con su payload y sus intentos, y permite reenviarla.
Rotar el secreto
Sección titulada «Rotar el secreto»En Studio, rota el secreto de un endpoint: el secreto anterior sigue firmando (como segundo v1) durante 24 horas, para que puedas desplegar el nuevo sin perder eventos.
¿Te ha resultado útil esta página?
Gracias. Leemos todas las respuestas.