Skip to content
Iniciar sesión
Veridien Docs

Convenciones

Todos los endpoints siguen las mismas convenciones de códigos de estado, errores, reintentos y paginación. Apréndelas una vez y valen en todas partes.

EstadoSignificado
200Correcto.
201Se ha creado un recurso (un huésped, un bloqueo o un cargo).
400Petición inválida: JSON mal formado o un parámetro que no pasó la validación.
401Fallo de autenticación: falta la clave de API o no es válida.
403La clave es válida pero no tiene el ámbito necesario.
404La ruta o el recurso no existe (o no es tuyo).
405La ruta existe, pero no para este método HTTP.
409Conflicto: sin disponibilidad, reutilización de una clave de idempotencia o saldo de fidelidad insuficiente.
429Límite de uso alcanzado. Reintenta después del tiempo de la cabecera Retry-After.
500Error interno del servidor.
503Mantenimiento. La plataforma no está disponible temporalmente. Reintenta después del tiempo de la cabecera Retry-After.

Cada fallo devuelve el estado correspondiente y un único objeto error:

{
  "error": {
    "type": "permission",
    "code": "insufficient_scope",
    "message": "Missing required scope: reservations:write.",
    "request_id": "req_a1b2c3d4e5"
  }
}
  • type: la categoría: invalid_request, authentication, permission, not_found, conflict, rate_limit o server.
  • code: un identificador estable y legible por máquina. Bifurca por este valor, no por message.
  • message: una explicación legible por personas. Puedes registrarla en el log; no la analices.
  • param: el campo de la petición que provocó el error. Solo aparece en los errores 400 de validación de campos, y se omite en los demás.
  • estimated_end: una marca de tiempo ISO con la hora prevista de fin de una ventana de mantenimiento. Solo aparece en los 503, y solo cuando se ha fijado una hora de fin. Es más precisa que la cabecera Retry-After, que se deriva de ella, así que úsala para mostrar un estado del tipo "volvemos a las".
  • request_id: identifica la petición de forma única. Inclúyelo cuando contactes con soporte.

Antes el código que el mensaje

El texto de message puede cambiar; code no. Gestiona los errores bifurcando por error.code (por ejemplo, no_availability, rate_plan_not_found, insufficient_points).

Códigos habituales con los que te encontrarás:

CódigoTipoCuándo
missing_api_key / invalid_api_keyauthenticationFalta la cabecera Authorization, o la clave es desconocida, está desactivada o ha caducado.
insufficient_scopepermissionLa clave no tiene el ámbito del endpoint.
invalid_parameters / invalid_jsoninvalid_requestUn campo no pasó la validación, o el cuerpo no era JSON válido.
unknown_routenot_foundNingún endpoint coincide con la ruta.
no_availabilityconflictEl tipo de habitación está agotado para las fechas pedidas.
idempotency_key_reuseconflictSe reutilizó una Idempotency-Key con un cuerpo de petición distinto.
idempotency_in_progressconflictUna petición anterior con la misma Idempotency-Key sigue en curso. Reintenta en breve.
insufficient_pointsconflictUn canje de fidelidad supera el saldo disponible.
rate_limitedrate_limitSe superó el límite de peticiones por clave.
maintenance_modeserverLa plataforma está en una ventana de mantenimiento. Reintenta después del tiempo de la cabecera Retry-After.

Todos los identificadores de recursos de Veridien son UUID, por ejemplo 7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27. La referencia de reserva que ve el huésped es otra cosa: confirmation_code es un código corto y legible (por ejemplo B7XKQ4M2NZ) que se muestra a huéspedes y personal, y nunca se usa como identificador de recurso. Los identificadores de petición llevan el prefijo req_. Los campos que aportas tú, como payment_reference, son opacos para Veridien y conservan el formato que use tu sistema.

Las peticiones POST y PATCH son las que cambian el estado: crear un huésped, bloquear inventario, confirmar una reserva, canjear puntos, anotar un cargo. Para que los reintentos sean seguros, envía una cabecera Idempotency-Key con un valor único (un UUID funciona bien):

curl -X POST https://veridien.app/api/v1/holds \
  -H "Authorization: Bearer vrdn_live_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1d2c9a-8b3e-4a17-9c2f-1e5b7d0a4c83" \
  -d '{ "room_type_id": "9b2f6c3e-8d1a-4f5b-a7c9-4e0d2b8f1a63", "rate_plan_id": "5c1e8f4a-2b7d-4a9c-8e6f-1d3b9a5c7e02", "check_in": "2026-08-01", "check_out": "2026-08-04", "guest_id": "3f8a2c1b-9d4e-4c6a-8b7f-5e2d1a9c0b34", "adults": 2 }'
  • La primera petición con una clave dada se ejecuta con normalidad y su respuesta se guarda.
  • Un reintento con la misma clave y el mismo cuerpo reproduce la respuesta guardada: ni un segundo bloqueo, ni un segundo cargo.
  • Reutilizar la clave con un cuerpo distinto devuelve 409 idempotency_key_reuse.
  • Enviar la misma clave en paralelo, antes de que haya terminado la primera petición, devuelve 409 idempotency_in_progress. Reintenta un momento después y obtendrás la respuesta guardada. La clave se reserva antes de ejecutar la operación, así que la segunda petición nunca llega a ejecutarla.
  • Una petición que falla libera su clave, así que un reintento honesto vuelve a ejecutarse en lugar de reproducir el fallo. Solo se guardan las respuestas correctas: un 409 no_availability por un agotamiento puntual no se reproduce eternamente cuando la habitación vuelve a estar libre.

Las claves están acotadas a cada clave de API. Usa una Idempotency-Key nueva por cada operación lógica.

Confirmar es doblemente idempotente

Confirmar un bloqueo (POST /holds/{id}/confirm) es además idempotente sobre su payment_reference: volver a confirmar una reserva ya confirmada, o repetir la misma referencia de pago, devuelve el resultado confirmado existente con "already_confirmed": true en lugar de volver a cobrar.

GET /reservations pagina con limit y offset. Los demás endpoints de listado (/room-types, /services, /rate-plans) devuelven el conjunto completo del establecimiento y no paginan.

ParámetroValor por defectoMáximoSignificado
limit25100Cuántos registros devolver.
offset010000Cuántos registros saltar.

La respuesta envuelve los resultados en data e indica si quedan más:

{
  "has_more": true,
  "data": [ /* ... */ ]
}

Para pedir la página siguiente, suma limit a tu offset anterior. Detente cuando has_more sea false.

Todo valor monetario es una cadena decimal, nunca un número en coma flotante: "1310.40", no 1310.4. Analízalos con un tipo decimal, no con uno binario de coma flotante.

Un establecimiento tiene una moneda base, y una cuenta puede llevar líneas en varias monedas a la vez (un cargo de habitación en USD con una línea de restaurante en MVR es lo normal). De ahí salen dos reglas:

Los importes en monedas distintas nunca se suman entre sí. Allí donde se informa de un saldo, un array balances da los importes reales por moneda, y esa es la cifra fiable:

"balances": [
  { "currency": "USD", "charges": "1310.40", "payments": "0.00", "balance": "1310.40" },
  { "currency": "MVR", "charges": "1500.00", "payments": "1500.00", "balance": "0.00" }
]

Una cuenta está settled solo cuando no se debe nada en ninguna moneda. Una deuda en USD nunca se cancela con un crédito en MVR.

Los totales planos son una valoración, y pueden ser null. Campos como balance, total_charges y folio_balance son cifras de conveniencia valoradas en la moneda base del establecimiento, construidas a partir del tipo de cambio congelado en cada línea en el momento en que se escribió. Como el tipo está congelado, un cambio posterior nunca altera el valor declarado de un cargo existente. Si una línea está en una moneda para la que el establecimiento no tiene tipo configurado, no se puede valorar, y esos campos son null en lugar de un número equivocado. Trata el caso null antes de hacer cuentas.

Los límites de uso funcionan con un cubo con fugas (token bucket), por clave de API. Tu cubo tiene capacidad para 600 fichas y se rellena a un ritmo constante de 10 fichas por segundo (600 por minuto). Cada petición gasta una ficha:

  • Una ráfaga puede gastar el cubo entero de golpe, hasta 600 peticiones seguidas.
  • El rendimiento sostenido es el ritmo de recarga, 10 peticiones por segundo.

Cuando el cubo está vacío, las peticiones devuelven 429 con una cabecera Retry-After. Espera al menos los segundos indicados y reintenta. Es mejor cachear las lecturas (/property, /room-types y /services llevan un Cache-Control corto; /availability y /rates son inventario en vivo y a propósito no se cachean, así que no los caches tú tampoco) y evitar los bucles de sondeo agresivos.

Cada respuesta, correcta o con error, lleva asociado un request_id (que también se devuelve en los cuerpos de error y en /me). Guárdalo en el log. Cuando comuniques una incidencia, el identificador de petición permite a soporte rastrear la llamada exacta.