Skip to content
Se connecter
Veridien Docs

Conventions

Tous les endpoints suivent les mêmes conventions pour les codes de statut, les erreurs, les nouvelles tentatives et la pagination. Apprenez-les une fois, elles s'appliquent partout.

StatutSignification
200Succès.
201Une ressource a été créée (un client, un blocage ou une ligne de frais).
400Requête invalide : JSON mal formé ou paramètre qui n'a pas passé la validation.
401Échec de l'authentification : clé d'API absente ou invalide.
403La clé est valide mais n'a pas la portée requise.
404La route ou la ressource n'existe pas (ou ne vous appartient pas).
405Le chemin existe, mais pas pour cette méthode HTTP.
409Conflit : plus de disponibilité, réutilisation d'une clé d'idempotence ou solde de fidélité insuffisant.
429Limite de débit atteinte. Réessayez après le délai de l'en-tête Retry-After.
500Erreur interne du serveur.
503Maintenance. La plateforme est temporairement indisponible. Réessayez après le délai de l'en-tête Retry-After.

Chaque échec renvoie le statut correspondant et un unique objet error :

{
  "error": {
    "type": "permission",
    "code": "insufficient_scope",
    "message": "Missing required scope: reservations:write.",
    "request_id": "req_a1b2c3d4e5"
  }
}
  • type : la catégorie, parmi invalid_request, authentication, permission, not_found, conflict, rate_limit et server.
  • code : un identifiant stable, lisible par une machine. Faites vos branchements dessus, pas sur message.
  • message : une explication lisible par un humain. Vous pouvez le journaliser, ne l'analysez pas.
  • param : le champ de la requête à l'origine de l'erreur. Présent uniquement sur les erreurs de validation de champ en 400, omis sinon.
  • estimated_end : un horodatage ISO indiquant quand une fenêtre de maintenance devrait se terminer. Présent uniquement sur les 503, et seulement quand une heure de fin a été définie. Il est plus précis que l'en-tête Retry-After, qui en découle, préférez-le donc pour afficher un état « de retour à ».
  • request_id : identifie la requête de manière unique. Joignez-le quand vous contactez le support.

Le code plutôt que le message

Le texte de message peut changer, code non. Branchez votre gestion des erreurs sur error.code (par exemple, no_availability, rate_plan_not_found, insufficient_points).

Les codes que vous rencontrerez le plus souvent :

CodeTypeCas
missing_api_key / invalid_api_keyauthenticationL'en-tête Authorization est absent, ou la clé est inconnue, désactivée ou expirée.
insufficient_scopepermissionLa clé n'a pas la portée de l'endpoint.
invalid_parameters / invalid_jsoninvalid_requestUn champ n'a pas passé la validation, ou le corps n'était pas du JSON valide.
unknown_routenot_foundAucun endpoint ne correspond au chemin.
no_availabilityconflictLe type de chambre est complet pour les dates demandées.
idempotency_key_reuseconflictUn Idempotency-Key a été réutilisé avec un corps de requête différent.
idempotency_in_progressconflictUne requête antérieure portant le même Idempotency-Key est encore en cours. Réessayez dans un instant.
insufficient_pointsconflictUne utilisation de points de fidélité dépasse le solde disponible.
rate_limitedrate_limitLa limite de requêtes par clé a été dépassée.
maintenance_modeserverLa plateforme est en fenêtre de maintenance. Réessayez après le délai de l'en-tête Retry-After.

Tous les identifiants de ressources Veridien sont des UUID, par exemple 7d5dc2ea-1f4e-4bfa-9a52-6c3f08b41e27. La référence de réservation montrée au client est distincte : confirmation_code est un code court et lisible (par exemple B7XKQ4M2NZ) affiché aux clients et au personnel, jamais utilisé comme identifiant de ressource. Les identifiants de requête sont préfixés par req_. Les champs que vous fournissez, comme payment_reference, sont opaques pour Veridien et conservent le format qu'utilise votre système.

Les requêtes POST et PATCH sont celles qui changent l'état : créer un client, bloquer des disponibilités, confirmer une réservation, utiliser des points, passer des frais. Pour rendre les nouvelles tentatives sûres, envoyez un en-tête Idempotency-Key avec une valeur unique (un UUID convient 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 première requête portant une clé donnée s'exécute normalement et sa réponse est mémorisée.
  • Une nouvelle tentative avec la même clé et le même corps rejoue la réponse mémorisée : pas de deuxième blocage, pas de deuxième frais.
  • Réutiliser la clé avec un corps différent renvoie 409 idempotency_key_reuse.
  • Envoyer la même clé en parallèle, avant que la première requête soit terminée, renvoie 409 idempotency_in_progress. Réessayez après un instant et vous obtiendrez la réponse mémorisée. La clé est réservée avant que l'opération ne s'exécute, la deuxième requête ne l'exécute donc jamais.
  • Une requête qui échoue libère sa clé, une nouvelle tentative légitime s'exécute donc vraiment au lieu de rejouer l'échec. Seules les réponses réussies sont mémorisées : un 409 no_availability dû à un complet passager n'est pas rejoué indéfiniment une fois la chambre libérée.

Les clés d'idempotence sont cloisonnées par clé d'API. Utilisez un Idempotency-Key neuf pour chaque opération logique.

La confirmation est doublement idempotente

Confirmer un blocage (POST /holds/{id}/confirm) est aussi idempotent sur son payment_reference : reconfirmer une réservation déjà confirmée, ou rejouer la même référence de paiement, renvoie le résultat confirmé existant avec "already_confirmed": true au lieu de facturer à nouveau.

GET /reservations se pagine avec limit et offset. Les autres endpoints de liste (/room-types, /services, /rate-plans) renvoient l'ensemble complet pour l'établissement et ne se paginent pas.

ParamètrePar défautMaxSignification
limit25100Combien d'enregistrements renvoyer.
offset010000Combien d'enregistrements sauter.

La réponse enveloppe les résultats dans data et indique s'il en reste :

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

Pour aller à la page suivante, ajoutez limit à votre offset précédent. Arrêtez-vous quand has_more vaut false.

Toute valeur monétaire est une chaîne décimale, jamais un nombre flottant : "1310.40", pas 1310.4. Analysez-les avec un type décimal, pas avec un flottant binaire.

Un établissement a une seule devise de base, et une note peut porter des lignes dans plusieurs devises à la fois (une facture de chambre en USD avec une ligne de restaurant en MVR est normale). Deux règles en découlent :

Des montants dans des devises différentes ne sont jamais additionnés. Partout où un solde est indiqué, un tableau balances donne les montants réels par devise, et c'est ce chiffre qu'il faut croire :

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

Une note n'est settled que lorsque rien n'est dû dans aucune devise. Une dette en USD n'est jamais annulée par un crédit en MVR.

Les totaux à plat sont une valorisation, et peuvent valoir null. Des champs comme balance, total_charges et folio_balance sont des chiffres de commodité, valorisés dans la devise de base de l'établissement à partir du taux de change figé sur chaque ligne au moment de son écriture. Comme le taux est figé, un changement de taux ultérieur ne modifie jamais la valeur affichée d'un frais existant. Si une ligne est dans une devise pour laquelle l'établissement n'a pas de taux configuré, elle ne peut pas être valorisée, et ces champs valent null plutôt qu'un chiffre faux. Traitez le cas null avant de faire des calculs.

Les limites de débit reposent sur un seau percé (seau à jetons), par clé d'API. Votre seau contient jusqu'à 600 jetons et se remplit au rythme constant de 10 jetons par seconde (600 par minute). Chaque requête dépense un jeton :

  • Une rafale peut vider le seau d'un coup, jusqu'à 600 requêtes à la suite.
  • Le débit soutenu est celui du remplissage, 10 requêtes par seconde.

Quand le seau est vide, les requêtes renvoient 429 avec un en-tête Retry-After. Patientez au moins le nombre de secondes indiqué, puis réessayez. Préférez mettre les lectures en cache (/property, /room-types et /services portent un Cache-Control court ; /availability et /rates reflètent les disponibilités en direct et ne sont volontairement pas mis en cache, ne les mettez donc pas en cache non plus) et évitez les boucles d'interrogation serrées.

Chaque réponse, en succès comme en erreur, est associée à un request_id (également renvoyé dans les corps d'erreur et par /me). Journalisez-le. Quand vous signalez un problème, cet identifiant permet au support de retrouver l'appel exact.