Webhooks
1tokens envía una solicitud POST firmada a la URL HTTPS que registres en la consola cada vez que ocurre un evento suscrito. Crea un endpoint en la página Webhooks y marca los eventos que quieras; los endpoints nuevos entran en vigor en menos de 30 segundos.
Catálogo de eventos
Modelo
| Tipo | Nombre | Campos de data |
|---|---|---|
model.listed | Modelo publicado | model tenant_id previous_status status actor |
model.delisted | Modelo retirado | model tenant_id previous_status status actor |
model.deprecated | Modelo obsoleto | model previous_status status actor |
model.price.changed | Precio cambiado | model tenant_id pricing_status sale_price_mode multiplier price changes actor |
model.user_price.changed | Precio de usuario cambiado | model user_id multiplier changes actor |
model.updated | Modelo actualizado | model changes actor |
API Key
| Tipo | Nombre | Campos de data |
|---|---|---|
api_key.created | Key creada | api_key actor |
api_key.updated | Key actualizada | api_key changes actor |
api_key.revoked | Key revocada | api_key previous_status status actor |
api_key.expired | Key caducada | api_key actor |
api_key.quota.exhausted | Cuota agotada | api_key quota_limit_usd consumed_usd actor |
api_key.rate_window.exceeded | Límite de ventana superado | api_key window limit_usd consumed_usd actor |
Cuenta
| Tipo | Nombre | Campos de data |
|---|---|---|
account.balance.low | Saldo bajo | account threshold_usd request_id actor |
account.balance.exhausted | Saldo agotado | account reason request_id actor |
account.credit.topup | Recarga | account amount_usd amount_credits source order_no actor |
account.credit.adjusted | Ajuste de saldo | account delta_usd delta_credits kind reason actor |
account.trial.granted | Prueba concedida | account amount_credits actor |
account.disabled | Cuenta desactivada | account previous_status status actor |
account.enabled | Cuenta activada | account previous_status status actor |
account.password.reset | Contraseña restablecida | account actor |
Pedido
| Tipo | Nombre | Campos de data |
|---|---|---|
order.created | Pedido creado | order actor |
order.paid | Pedido pagado | order paid_at previous_status status actor |
order.failed | Pago fallido | order reason previous_status status actor |
order.redeemed | Código canjeado | order code_masked actor |
Suscripción
| Tipo | Nombre | Campos de data |
|---|---|---|
subscription.started | Suscripción iniciada | subscription previous_status status actor |
subscription.renewed | Suscripción renovada | subscription actor |
subscription.upgraded | Suscripción mejorada | subscription changes actor |
subscription.cancelled | Suscripción cancelada | subscription previous_status status actor |
subscription.payment_failed | Renovación fallida | subscription reason actor |
subscription.quota.exhausted | Cuota agotada | subscription request_id actor |
Tarea
| Tipo | Nombre | Campos de data |
|---|---|---|
task.video.succeeded | Vídeo listo | task video_count actor |
task.video.failed | Vídeo fallido | task actor |
task.generation.succeeded | Generación lista | task media output_count actor |
task.generation.failed | Generación fallida | task media actor |
Contenido
| Tipo | Nombre | Campos de data |
|---|---|---|
content.changelog.published | Changelog publicado | entry actor |
content.article.published | Artículo publicado | article tenant_id previous_status status actor |
content.article.unpublished | Artículo retirado | article tenant_id previous_status status actor |
Webhook
| Tipo | Nombre | Campos de data |
|---|---|---|
webhook.endpoint.auto_disabled | Endpoint desactivado | endpoint reason consecutive_failures actor |
Formato del payload
Todos los eventos comparten el mismo sobre: id (id único del evento), type, domain, created_at (ISO 8601 UTC), api_version y data. Dentro de data las claves van en snake_case, las fechas terminan en _at, los importes son cadenas decimales (_usd / _credits) y los valores ausentes son null explícitos. Un mismo evento puede entregarse más de una vez por los reintentos; deduplica por id.
{ "id": "evt_01JBXK6Q3N7Y8R2V4W5X6Z7A8B", "type": "model.price.changed", "domain": "model", "created_at": "2026-11-04T08:12:33Z", "api_version": "2026-11-04", "data": { }}Cabeceras de la solicitud
POST https://your-server.example/webhooksContent-Type: application/jsonUser-Agent: Webhooks/1.0X-Event-Id: evt_01JBXK6Q3N7Y8R2V4W5X6Z7A8BX-Event-Type: model.price.changedX-Delivery-Id: 123456X-Timestamp: 1762243953X-Signature: v1=5f1c…Verificar la firma
Calcula HMAC-SHA256 con el secreto mostrado al crear el endpoint sobre la cadena valor de X-Timestamp + . + cuerpo crudo de la solicitud, y compáralo en tiempo constante con el hexadecimal que sigue a v1= en X-Signature. Rechaza las solicitudes cuya marca de tiempo difiera de la actual en más de 5 minutos. Responde 2xx primero y procesa después; toda la respuesta debe completarse en menos de 10 segundos.
import { createHmac, timingSafeEqual } from "node:crypto";export function verify(secret, headers, rawBody) { const ts = headers["x-timestamp"]; if (Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false; const expected = createHmac("sha256", secret).update(ts + "." + rawBody).digest("hex"); const given = String(headers["x-signature"]).replace(/^v1=/, ""); return given.length === expected.length && timingSafeEqual(Buffer.from(given, "hex"), Buffer.from(expected, "hex"));}import hmac, hashlib, timedef verify(secret: str, headers: dict, raw_body: bytes) -> bool: ts = headers["X-Timestamp"] if abs(time.time() - int(ts)) > 300: return False expected = hmac.new(secret.encode(), f"{ts}.".encode() + raw_body, hashlib.sha256).hexdigest() given = headers["X-Signature"].removeprefix("v1=") return hmac.compare_digest(given, expected)func verify(secret string, ts, sig string, body []byte) bool { t, _ := strconv.ParseInt(ts, 10, 64) if math.Abs(float64(time.Now().Unix()-t)) > 300 { return false } mac := hmac.New(sha256.New, []byte(secret)) mac.Write([]byte(ts + ".")) mac.Write(body) expected := hex.EncodeToString(mac.Sum(nil)) return hmac.Equal([]byte(strings.TrimPrefix(sig, "v1=")), []byte(expected))}Reintentos y desactivación automática
Una respuesta distinta de 2xx o la ausencia de respuesta en 10 segundos cuenta como fallo. Cada entrega se intenta hasta 7 veces con los intervalos de la tabla; después se marca como agotada. Un endpoint con 10 entregas consecutivas agotadas se desactiva automáticamente y se te avisa por correo; vuelve a activarlo en la consola cuando lo hayas corregido. Cualquier entrega puede reenviarse manualmente desde la consola.
| Intento | Espera tras el anterior |
|---|---|
| 1 | 0 |
| 2 | 1 min |
| 3 | 5 min |
| 4 | 30 min |
| 5 | 2 h |
| 6 | 6 h |
| 7 | 24 h |
Requisitos del endpoint
La URL debe ser una dirección HTTPS accesible públicamente; se rechazan los nombres de host que resuelven a rangos privados, de loopback o de enlace local. No se siguen redirecciones y se leen como máximo 64 KB del cuerpo de la respuesta.

