Guía: conectar un ERP
Del alta de la integración a la primera sincronización completa, con lo mínimo que necesita un ERP: qué servicios hubo, para quién, cuánto, y con qué id tuyo.
0 · Decide qué necesitas
| Necesitas | Scope | Por qué |
|---|---|---|
| Servicios y su estado | bookings:read | La base de todo. |
| Clientes de WAT ↔ cuentas del ERP | customers:read | Para mapear hoteles y agencias. |
| Importes e IVA | pricing:read | Solo si el ERP factura o contabiliza. |
| Nombre del pasajero en la factura | passengers:read | Solo si va en el documento. Si no, no lo pidas. |
| Enterarte al instante | webhooks:read · webhooks:write | Sin sondear. |
| Tu número de pedido/factura en WAT | links:read · links:write | Reconciliar sin tablas intermedias. |
| Reconciliar tras una caída | events:read | La lista de lo que pasó. |
1 · Alta de la integración y la clave
Pide a We Are Transfers (o crea desde tu panel, cuando esté disponible) una integración de tipo erp con los scopes de arriba, y una clave live. Guarda la clave en tu gestor de secretos y comprueba con GET /v1/integrations/me que los scopes son los que esperabas.
2 · Carga inicial
Descarga los clientes y las reservas de un periodo con paginación, y guarda tus mapeos:
const API = 'https://wearetransfers.com/api/v1';
const h = { Authorization: `Bearer ${process.env.WAT_API_KEY}` };
async function* paginas(path, params) {
let cursor = null;
do {
const q = new URLSearchParams({ ...params, limit: '100', ...(cursor ? { cursor } : {}) });
const res = await fetch(`${API}${path}?${q}`, { headers: h });
if (!res.ok) throw new Error(`${path} ${res.status} ${res.headers.get('x-wat-request-id')}`);
const page = await res.json();
yield* page.data;
cursor = page.next_cursor;
} while (cursor);
}
// clientes → cuentas del ERP (por nombre la primera vez, por id después)
for await (const c of paginas('/customers', { active: 'true' })) await upsertCuenta({ watId: c.id, nombre: c.name, grupo: c.group?.name });
// servicios completados de septiembre
for await (const b of paginas('/bookings', { status: 'completed', pickup_from: '2026-09-01T00:00:00Z', pickup_to: '2026-09-30T23:59:59Z' })) {
await upsertServicio(b);
}pickup_at es la hora de recogida; created_at, cuándo se creó. Para un cierre mensual filtra por recogida. Todas las fechas son ISO 8601 con zona horaria.
3 · Tu id en cada reserva
Al crear el servicio en tu ERP, guarda su id en WAT. A partir de ahí cada reserva —en la API y en los webhooks— trae tu external_id:
await fetch(`${API}/bookings/${b.id}/external-id`, {
method: 'PUT',
headers: { ...h, 'Content-Type': 'application/json', 'Idempotency-Key': `erp-link-${b.id}` },
body: JSON.stringify({ external_id: servicioErp.numero }),
});4 · Mantente al día
Crea un webhook suscrito a booking.completed, booking.cancelled, booking.no_show y booking.updated, verifica la firma y actualiza el servicio en tu ERP con data. Detalle en Actualizaciones en tiempo real.
5 · Cierre y reconciliación
Antes de facturar el mes, vuelve a recorrer GET /bookings?status=completed&pickup_from…: es barato (100 por página) y cubre cualquier webhook perdido. Lo que tenga external_id: null no lo has procesado. Ver Sincronizar servicios completados.