Saltar al contenido
Cómo funcionan
Contrato OpenAPI 3.1: openapi.yaml
Webhooks

Webhooks: cómo funcionan

We Are Transfers hace POST a tu URL cada vez que una reserva cambia. Firmado, con reintentos, y con el cuerpo recortado a los scopes de tu integración.

El camino de un evento

text
reserva cambia ──► evento en cola (mismo commit)
                       │
                       ▼  worker, cada minuto
              una entrega por webhook suscrito
                       │
                       ▼  POST https://tu-url  (firma HMAC, 10 s de espera)
                 2xx → entregado · otra cosa → reintento
  • El evento se escribe en la misma transacción que el cambio de la reserva: no se pierde si el worker está caído.
  • Cada webhook recibe su propia entrega: uno caído no frena a los demás.
  • El cuerpo se construye al entregar, con los scopes de la integración en ese momento. Sin passengers:read nunca llega un teléfono.
  • El orden no está garantizado entre eventos distintos. Usa created_at y, ante la duda, vuelve a leer la reserva.

La petición que recibes

CabeceraQué es
X-WAT-EventTipo de evento (booking.completed…).
X-WAT-Event-IdUUID del evento. Se repite en los reintentos: deduplica por él.
X-WAT-DeliveryUUID de la entrega. Es el mismo en todos los reintentos de esa entrega, y el id que ves en GET /webhooks/{id}/deliveries.
X-WAT-AttemptNúmero de intento de esta entrega, empezando en 1.
X-WAT-TimestampSegundos Unix en el momento de firmar.
X-WAT-Signaturev1= + HMAC-SHA256 hex de timestamp + "." + cuerpo. Durante el solape de una rotación de secreto van dos, separadas por coma. Ver Firmas.
Content-Typeapplication/json.
User-AgentWAT-Webhooks/1.
json
{
  "id": "6d2e1f0a-9b8c-4d7e-a6f5-4c3b2a1d0e9f",
  "type": "booking.completed",
  "version": 1,
  "created_at": "2026-09-18T10:42:07.318Z",
  "organization": {
    "id": "9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d"
  },
  "resource": {
    "type": "booking",
    "id": "0c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f"
  },
  "changes": [
    "status"
  ],
  "previous_status": "en_curso",
  "data": {
    "id": "0c1d2e3f-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
    "reference": "10031234",
    "external_id": "VLC-2026-000123",
    "status": "completed",
    "service_type": "transfer",
    "hours": null,
    "pickup_at": "2026-09-18T08:30:00+00:00",
    "end_at": null,
    "pickup": {
      "address": "Aeropuerto de Valencia (VLC)",
      "lat": 39.4893,
      "lng": -0.4816
    },
    "destination": {
      "address": "Hotel Las Arenas, Valencia",
      "lat": 39.4735,
      "lng": -0.3245
    },
    "distance_km": 12.4,
    "flight": {
      "number": "VY1234",
      "pending": false
    },
    "passengers": {
      "count": 2,
      "luggage": 2,
      "luggage_big": 2,
      "luggage_small": 0,
      "baby_seats": 0,
      "child_seats": 0,
      "booster_seats": 0,
      "wheelchair": false
    },
    "vehicle_category": "sedan",
    "customer": {
      "id": "7e6d5c4b-3a2b-4c1d-9e8f-7a6b5c4d3e2f",
      "name": "Hotel Las Arenas"
    },
    "assignment": {
      "external": false,
      "driver": {
        "id": "1a2b3c4d-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
        "name": "Marta Gil",
        "nickname": "Marta"
      },
      "vehicle": {
        "id": "5f4e3d2c-1b0a-4f9e-8d7c-6b5a4f3e2d1c",
        "plate": "1234 KLM",
        "model": "Mercedes Clase E"
      }
    },
    "role": "originator_and_executor",
    "channel": "customer_engine",
    "confirmation": {
      "mode": "auto",
      "confirmed_at": "2026-09-17T18:02:11+00:00"
    },
    "event_reference": null,
    "created_at": "2026-09-17T18:02:11.204Z"
  }
}
CampoQué es
idId de la entrega (igual que X-WAT-Delivery).
type · versionTipo de evento y versión del cuerpo (1).
created_atCuándo ocurrió el evento.
organization.idTu organización.
resourcetype e id del recurso (booking; webhook en el evento de prueba).
changesColumnas internas que cambiaron. Las del pasajero solo con passengers:read.
previous_statusEstado interno anterior (confirmada, en_curso…).
dataLa reserva completa, con la forma de Booking y según tus scopes. null en el evento de prueba.

Qué tiene que hacer tu servidor

  1. Leer el cuerpo crudo (bytes, sin parsear) y verificar la firma.
  2. Rechazar timestamps con más de 5 minutos de diferencia.
  3. Responder 2xx en menos de 10 segundos. Encola el trabajo pesado y responde ya.
  4. Deduplicar por X-WAT-Event-Id.
  5. Si necesitas más de lo que trae data, llamar a GET /v1/bookings/{id}.
Redirecciones y 3xx

No se siguen. Un 301/302 cuenta como fallo permanente. Apunta directamente a la URL final.

Activación

Los webhooks (y la cola de eventos) se activan por organización, junto con la API. Hasta entonces puedes crear los destinos y probarlos con un evento de prueba.

Webhooks: cómo funcionan · API de WAT