Referencia: endpoints de webhooks
Los destinos HTTPS de tu integración. Hasta 10 por integración. El secreto de firma se enseña una sola vez.
Todos los webhooks de esta integración (sin paginación).
Petición
curl https://wearetransfers.com/api/v1/webhooks \
-H "Authorization: Bearer $WAT_API_KEY"Respuesta
{
"data": [
{
"id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
"url": "https://erp.ejemplo.com/hooks/wat",
"events": [
"booking.completed",
"booking.cancelled"
],
"active": true,
"description": "ERP · servicios terminados",
"consecutive_failures": 0,
"disabled_at": null,
"disabled_reason": null,
"created_at": "2026-09-18T09:00:00.000Z",
"updated_at": "2026-09-18T09:00:00.000Z"
}
]
}Crea un destino. La respuesta trae secret solo esta vez. Admite Idempotency-Key. Las reglas de la URL están en Seguridad: https, puerto 443, sin credenciales, destino público.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
url * | body | string | https://…, ≤ 500 caracteres. |
events * | body | string[] | Tipos de evento, o ["*"] para todos. |
description | body | string | ≤ 200 caracteres. |
Petición
curl -X POST https://wearetransfers.com/api/v1/webhooks \
-H "Authorization: Bearer $WAT_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: crear-webhook-erp-1" \
-d '{"url":"https://erp.ejemplo.com/hooks/wat","events":["booking.completed","booking.cancelled"],"description":"ERP · servicios terminados"}'Respuesta · 201
{
"id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
"url": "https://erp.ejemplo.com/hooks/wat",
"events": [
"booking.completed",
"booking.cancelled"
],
"active": true,
"description": "ERP · servicios terminados",
"consecutive_failures": 0,
"disabled_at": null,
"disabled_reason": null,
"created_at": "2026-09-18T09:00:00.000Z",
"updated_at": "2026-09-18T09:00:00.000Z",
"secret": "whsec_2Xk9fJ3mQpL8vT1nR6wY4bH0cD7sG5aZ9eU2iO8kM3q"
}La réplica llega con Idempotent-Replayed: true, secret: null y secret_shown_once: true. El secreto no se guarda para poder repetirlo: se enseña en la primera respuesta y ya. Guárdalo antes de reintentar nada; si se perdió, crea otro webhook y borra este.
Un webhook de esta integración.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
id * | path | uuid | Id del webhook. |
Petición
curl https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f \
-H "Authorization: Bearer $WAT_API_KEY"Respuesta
{
"id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
"url": "https://erp.ejemplo.com/hooks/wat",
"events": [
"booking.completed",
"booking.cancelled"
],
"active": true,
"description": "ERP · servicios terminados",
"consecutive_failures": 0,
"disabled_at": null,
"disabled_reason": null,
"created_at": "2026-09-18T09:00:00.000Z",
"updated_at": "2026-09-18T09:00:00.000Z"
}Cambia uno o más campos. active: true reactiva un webhook desactivado por fallos y pone el contador a cero. Un cuerpo vacío es 400.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
url | body | string | Misma validación que al crear. |
events | body | string[] | Sustituye la lista. |
description | body | string | null | ≤ 200. |
active | body | boolean | Pausar (false) o reactivar (true). |
Petición
curl -X PATCH https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f \
-H "Authorization: Bearer $WAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"active":true}'Respuesta
{
"id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
"url": "https://erp.ejemplo.com/hooks/wat",
"events": [
"booking.completed",
"booking.cancelled"
],
"active": true,
"description": "ERP · servicios terminados",
"consecutive_failures": 0,
"disabled_at": null,
"disabled_reason": null,
"created_at": "2026-09-18T09:00:00.000Z",
"updated_at": "2026-09-18T09:00:00.000Z"
}Borra el destino y su historial de entregas.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
id * | path | uuid | Id del webhook. |
Petición
curl -X DELETE https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f \
-H "Authorization: Bearer $WAT_API_KEY"Respuesta
{
"deleted": true
}Encola un evento webhook.test que entrega el mismo worker que los reales, firmado igual. Responde 202; la entrega se sigue en /deliveries. Ver Pruebas.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
id * | path | uuid | Id del webhook. |
Petición
curl -X POST https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f/test \
-H "Authorization: Bearer $WAT_API_KEY"Respuesta · 202
{
"delivery_id": "6d2e1f0a-9b8c-4d7e-a6f5-4c3b2a1d0e9f",
"event_id": "8b7a6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
"status": "pending"
}Secreto de firma nuevo, devuelto una sola vez. Durante overlap_minutes las entregas llevan las dos firmas separadas por coma, así que puedes desplegar sin corte. Ver Firmas.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
id * | path | uuid | Id del webhook. |
overlap_minutes * | body | integer | Obligatorio. 0–1440 minutos de solape; 0 = el anterior deja de valer ya. |
Petición
curl -X POST https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f/rotate-secret \
-H "Authorization: Bearer $WAT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"overlap_minutes": 60}'Respuesta
{
"id": "3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f",
"secret": "whsec_…",
"previous_secret_valid_until": "2026-09-21T11:00:00.000Z"
}Las últimas entregas del destino, de la más reciente a la más antigua. Sin cursor.
| Parámetro | Dónde | Tipo | Descripción |
|---|---|---|---|
id * | path | uuid | Id del webhook. |
limit | query | integer | 1–100, por defecto 25. Más de 100 se recorta a 100; menos de 1 o no entero es 400. |
Petición
curl "https://wearetransfers.com/api/v1/webhooks/3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f/deliveries?limit=2" \
-H "Authorization: Bearer $WAT_API_KEY"Respuesta
{
"data": [
{
"id": "a1b2c3d4-e5f6-4a7b-8c9d-0e1f2a3b4c5e",
"event_id": "8b7a6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
"event_type": "booking.completed",
"status": "failed",
"attempt": 2,
"max_attempts": 8,
"next_retry_at": "2026-09-18T10:44:10.000Z",
"last_status": 503,
"last_error": "HTTP 503",
"last_duration_ms": 1804,
"delivered_at": null,
"created_at": "2026-09-18T10:42:08.000Z"
},
{
"id": "6d2e1f0a-9b8c-4d7e-a6f5-4c3b2a1d0e9f",
"event_id": "8b7a6c5d-4e3f-4a2b-9c1d-0e9f8a7b6c5d",
"event_type": "booking.completed",
"status": "succeeded",
"attempt": 1,
"max_attempts": 8,
"next_retry_at": "2026-09-18T10:42:10.000Z",
"last_status": 200,
"last_error": null,
"last_duration_ms": 212,
"delivered_at": "2026-09-18T10:42:10.000Z",
"created_at": "2026-09-18T10:42:08.000Z"
}
]
}El objeto Webhook
| Campo | Tipo | Qué es |
|---|---|---|
id | uuid | Identificador. |
url | string | Destino https. |
events | string[] | Tipos suscritos o ["*"]. |
active | boolean | Si recibe entregas. |
description | string | null | Texto libre. |
consecutive_failures | integer | Fallos seguidos. A 100 se desactiva solo. |
disabled_at · disabled_reason | date-time | null · string | null | Cuándo y por qué se desactivó. |
secret | string | Solo en la respuesta de creación. whsec_…. |
El objeto WebhookDelivery
| Campo | Tipo | Qué es |
|---|---|---|
id | uuid | Id de la entrega (X-WAT-Delivery). |
event_id · event_type | uuid · EventType | El evento entregado. |
status | pending | delivering | succeeded | failed | dead | failed se reintentará; dead ya no. |
attempt · max_attempts | integer | Intentos hechos y tope (8; 3 para 4xx permanentes). |
next_retry_at | date-time | null | Cuándo se reintentará. |
last_status · last_error · last_duration_ms | … | Resultado del último intento. last_status es null en timeout o error de red. |
delivered_at | date-time | null | Cuándo se entregó (2xx). |
Una URL no permitida, un evento desconocido o el undécimo webhook responden 400 validation_error con details.field:
{
"error": {
"code": "validation_error",
"message": "Ese destino no está permitido",
"request_id": "req_9f8e7d6c5b4a39281706",
"details": {
"field": "url"
}
}
}