Webhooks
Digitra le avisa a tu sistema, con un POST firmado a la URL que registres, cada vez que una reserva creada por la API avanza: registro de huéspedes, firma del contrato, reportes a TRA y SIRE, cambios y cancelaciones.
1. Registrar tu endpoint
curl -X POST https://digitra.rentals/api/partners/webhooks \
-H "Authorization: Bearer $DIGITRA_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://tu-servidor.com/webhooks/digitra",
"events": ["*"],
"include_guests": true
}'
Respuesta 201:
{
"id": "0b7e9f2a-1c3d-4e5f-8a9b-0c1d2e3f4a5b",
"url": "https://tu-servidor.com/webhooks/digitra",
"events": ["*"],
"include_guests": true,
"is_active": true,
"created_at": "2026-09-30T15:04:05.000Z",
"secret_rotated_at": null,
"secret": "whsec_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
secretse muestra una sola vez. Guárdalo: con él verificas la firma. Si lo pierdes, rótalo.urltiene que ser HTTPS y pública.events: lista de eventos que quieres recibir, o["*"]para todos (es el valor por defecto).include_guests: si estrue, los eventosregistration.*traen los datos de los huéspedes (documento, nacionalidad, residencia, contacto). Por defecto esfalse: el evento avisa y tú consultas el detalle conGET …?include=guests. Elige según lo que tu sistema necesite guardar.- Máximo 5 endpoints activos por llave. La llave de pruebas y la de producción tienen endpoints distintos.
Otras operaciones:
| Operación | Endpoint |
|---|---|
| Listar tus endpoints | GET /api/partners/webhooks |
Cambiar URL, eventos o include_guests |
PATCH /api/partners/webhooks/{id} |
| Desactivar | DELETE /api/partners/webhooks/{id} |
| Rotar el secreto | POST /api/partners/webhooks/{id}/rotate-secret |
Enviar un evento de prueba (ping) |
POST /api/partners/webhooks/{id}/test |
| Historial de entregas | GET /api/partners/webhooks/deliveries |
| Reenviar un evento | POST /api/partners/webhooks/deliveries/{id}/redeliver |
Al rotar, el secreto viejo deja de valer en ese instante. Todo lo que salga desde entonces, incluidos los reintentos de eventos anteriores, va firmado con el nuevo.
2. Qué recibe tu servidor
POST /webhooks/digitra HTTP/1.1
Content-Type: application/json
User-Agent: Digitra-Webhooks/1.0
X-Digitra-Event-Id: evt_3f9a1c2b4d5e6f708192a3b4c5d6e7f8
X-Digitra-Event: registration.completed
X-Digitra-Timestamp: 1727710000
X-Digitra-Signature: sha256=5d41402abc4b2a76b9719d911017c592...
| Header | Contenido |
|---|---|
X-Digitra-Event-Id |
Id único del evento. Es igual al campo id del cuerpo. Úsalo para deduplicar. |
X-Digitra-Event |
Tipo de evento. |
X-Digitra-Timestamp |
Momento del envío, en segundos Unix. |
X-Digitra-Signature |
sha256= + HMAC-SHA256 en hexadecimal. |
Cuerpo
Todos los eventos comparten la misma forma:
{
"id": "evt_3f9a1c2b4d5e6f708192a3b4c5d6e7f8",
"type": "registration.completed",
"created_at": "2026-10-01T15:04:05.000Z",
"api_version": "2026-10-01",
"sandbox": false,
"data": {
"reservation_id": "manual-1727650000000",
"external_id": "65a1b2c3d4e5f6a7b8c9d0e1",
"source": "guesty",
"property_id": "3f1c2b9a-0d4e-4a51-9a7e-2b6f0c8d1e23",
"reservation_status": "confirmed",
"status": "pending_compliance",
"check_in": "2026-10-10",
"check_out": "2026-10-12",
"guests_count": 2,
"checkin_url": "https://digitra.rentals/checkin/8b0c4f7e-2a1d-4c3b-9e5f-6a7b8c9d0e1f",
"checkin_status": "completed",
"guests_registered": 2,
"contract_signed": false,
"tra": { "status": "pending", "sends_on": "2026-10-12", "reported_at": null, "mincit_code": null },
"sire": { "status": "pending", "foreign_guests": 1, "reported_at": null },
"metadata": { "guesty_listing": "64f1a2b3c4d5e6f7a8b9c0d1", "canal": "airbnb" },
"guests": [
{
"is_primary": true,
"tipo_documento": "Pasaporte",
"numero_documento": "X1234567",
"nombre": "Ana",
"apellido": "Ejemplo",
"nacionalidad": "US",
"fecha_nacimiento": "1990-01-01",
"email": "huesped@ejemplo.com",
"phone": "+15550000000",
"address": null,
"ciudad_residencia": "Miami",
"pais_residencia": "US",
"registered_at": "2026-10-01T15:03:58.000Z",
"document_uploaded": true
}
]
}
}
dataes la misma foto que devuelve la consulta de estado en ese momento.guestssolo aparece en los eventosregistration.*y solo si el endpoint tieneinclude_guests: true.metadataes lo que enviaste al crear la reserva, tal cual.api_versioncambia solo si algún día modificamos el contrato de forma incompatible. Agregar campos nuevos no se considera incompatible: tu código debe ignorar los campos que no conozca.
Tipos de documento posibles en tipo_documento: Pasaporte, C.C, C.E, T.I, R.C, D.E (documento extranjero, Mercosur/CAN), C.D (carné diplomático), PPT (Permiso por Protección Temporal).
3. Catálogo de eventos
| Evento | Cuándo llega |
|---|---|
reservation.created |
Se creó la reserva por la API. |
reservation.updated |
Cambiaron las fechas o el número de huéspedes. |
reservation.cancelled |
La reserva se canceló. Después de este evento no llega ninguno más para esa reserva. |
registration.updated |
Se registró un huésped, pero todavía faltan otros. |
registration.completed |
Se registraron todos los huéspedes. Si la propiedad exige contrato, status será pending_signature hasta que se firme. |
contract.signed |
El huésped firmó el contrato. |
tra.reported |
MinCIT aceptó el reporte TRA. data.tra.mincit_code trae el código asignado. |
tra.failed |
MinCIT rechazó el TRA. data.tra.warning explica el motivo cuando lo conocemos. |
sire.reported |
Migración Colombia aceptó el reporte SIRE de entrada. |
sire.failed |
Migración Colombia rechazó el reporte SIRE. |
ping |
Evento de prueba, cuando lo pides con /test. Llega siempre, sin importar los eventos suscritos. |
Si en una misma revisión cambian varias cosas (por ejemplo, el huésped completa el registro y firma), recibes un evento por cada cambio.
4. Verificar la firma
Digitra calcula la firma así:
firma = "sha256=" + hex( HMAC_SHA256( secreto, "{X-Digitra-Timestamp}.{cuerpo crudo}" ) )
Tu receptor debe:
- Tomar el cuerpo crudo, exactamente como llegó. No lo parsees y lo vuelvas a serializar antes de verificar: cambiaría los bytes y la firma no coincidiría.
- Rechazar el evento si
X-Digitra-Timestamptiene más de 5 minutos de diferencia con tu reloj. Esto evita que alguien reenvíe un evento viejo interceptado. - Calcular la firma esperada con tu secreto y compararla con
X-Digitra-Signatureen tiempo constante (crypto.timingSafeEqualen Node,hmac.compare_digesten Python). - Si no coincide, responder
401y descartar el evento.
Hay ejemplos probados en verificar-firma.js (Node.js) y verificar_firma.py (Python). Los verificamos contra firmas generadas por nuestro propio servidor.
Para probar tu verificación sin crear reservas, usa el evento de prueba:
curl -X POST https://digitra.rentals/api/partners/webhooks/{id}/test \
-H "Authorization: Bearer $DIGITRA_KEY"
{ "event_id": "evt_...", "delivered": true, "http_status": 200, "duration_ms": 184 }
5. Entrega y reintentos
- Éxito = tu servidor responde con un código
2xxen menos de 10 segundos. Cualquier otra cosa es un fallo:4xx,5xx, redirecciones3xx(no las seguimos) o timeout. - Reintentos con espera creciente: 1 min, 5 min, 30 min, 2 h, 6 h y 24 h. Son siete intentos en unas 32 horas. Después, el evento queda como
failed. - Responde rápido y procesa en segundo plano. Si tu lógica tarda, guarda el evento, responde
200y trabájalo después. - Los avisos se generan revisando los cambios cada pocos minutos, así que un evento puede llegar unos minutos después del hecho. Los avisos nunca frenan el registro del huésped ni los reportes a la autoridad.
Orden y duplicados
- El orden no está garantizado. Un reintento de
registration.updatedpuede llegar después deregistration.completed. Usadata.statusycreated_atpara quedarte con la foto más reciente, o consulta el estado conGETsi necesitas certeza. - Un evento puede llegar más de una vez (por ejemplo, si respondiste
200pero la conexión se cortó antes de que lo recibiéramos). Deduplica porX-Digitra-Event-Id: si ya lo procesaste, responde200y no hagas nada.
Historial y reenvío
curl "https://digitra.rentals/api/partners/webhooks/deliveries?status=failed&limit=50" \
-H "Authorization: Bearer $DIGITRA_KEY"
Filtros: status (pending, delivered, failed), event, external_id, limit (máx. 200). Cada entrega trae attempt_log con cada intento: fecha, código HTTP, duración y error.
Para reenviar un evento failed (o uno entregado que perdiste de tu lado):
curl -X POST https://digitra.rentals/api/partners/webhooks/deliveries/{id}/redeliver \
-H "Authorization: Bearer $DIGITRA_KEY"
Sale con el mismo event_id y un ciclo de reintentos completo.
6. Ambiente de pruebas
Con la llave dgt_test_ registras endpoints de prueba, separados de los de producción. Los eventos traen "sandbox": true y los reportes vienen con "simulated": true. Para recibir tra.failed o sire.failed, crea la reserva con "sandbox_simulate": "tra_failed" o "sire_failed".