Porte compatible OS-Travel (Octasoft)
Cette porte reproduit l'api OS-Travel d'Octasoft (V1 et V2) : mêmes méthodes, mêmes noms de champs, mêmes formats. Si votre système parle déjà à MyGo, Tunisia Beds ou Mouradi, il parle à la passerelle sans modification.
Transport
- URL —
POST {base}/api/hotel/<Méthode>(ex.{base}/api/hotel/HotelSearch). - Content-Type —
application/json(V2) etapplication/x-www-form-urlencoded(V1 envoie du JSON brut sans en-tête explicite : les deux sont acceptés). - Réponse — toujours HTTP 200, même en erreur métier : le client V1/V2 ne parse que le 200.
- Authentification —
Credential { Login, Password }dans chaque requête (saufBookingDetail).
Enveloppe d’erreur — HTTP 200 quand même
{
"ErrorMessage": {
"Code": 401,
"Description": "Invalid credentials."
}
}
En succès V2, ErrorMessage est toujours présent avec Code: null et
Description: null — ne testez jamais l'absence de ErrorMessage, testez
Code vide ou nul.
Méthodes
| Méthode | Équivalent porte Brave | Description |
|---|---|---|
ListCountry | GET /v1/{code}/reference/countries | Liste des pays |
ListCity | GET /v1/{code}/reference/cities | Liste des villes |
ListBoarding | GET /v1/{code}/reference/boardings | Types de repas |
ListCategorie | GET /v1/{code}/reference/categories | Catégories d'hôtel |
ListCurrency | GET /v1/{code}/reference/currencies | Devises |
ListHotel | GET /v1/{code}/hotels | Catalogue des hôtels exposés |
HotelDetail | GET /v1/{code}/hotels/{id} | Fiche éditoriale |
HotelSearch | POST /v1/{code}/availability | Recherche par ville ou liste d'hôtels |
BookingCreation (PreBooking) | POST /v1/{code}/checkrate + POST /v1/{code}/bookings | Pré-réservation puis confirmation |
BookingList | GET /v1/{code}/bookings | Liste des réservations |
BookingDetail | GET /v1/{code}/bookings/{ref} | Détail et statut |
BookingCancellation (PreCancelled) | POST /v1/{code}/bookings/{ref}/cancel | Simulation (PreCancelled) puis annulation |
Exemples complets
HotelSearch
Dates au format Y-m-d. City ou Hotels (liste d'identifiants). Les Rooms existent en deux dialectes, acceptés tous les deux :
- V1 — chaînes :
{ "Adult": "2", "Child": ["3", "8"] }(cléChildabsente si aucun enfant) - V2 — entiers :
{ "Adult": 2, "Child": [3, 8] }
Requête — POST /api/hotel/HotelSearch
{
"Credential": { "Login": "demo_os_login", "Password": "demo_os_password" },
"SearchDetails": {
"BookingDetails": {
"CheckIn": "2027-01-15",
"CheckOut": "2027-01-20",
"City": 146070
},
"Filters": {
"Category": [],
"OnlyAvailable": true
},
"Rooms": [{ "Adult": 2, "Child": [8] }]
}
}
La réponse est un tableau HotelSearch, une entrée par source (contrat direct), avec le Token (= notre rateKey) à conserver :
Réponse — 200
{
"HotelSearch": [
{
"Hotel": { "Id": 1803258, "Image": "https://…/thumb.jpg" },
"Source": "12",
"Token": "rk_x9F2kQ8example",
"Price": {
"Boarding": [
{
"Id": 16,
"Name": "Petit-déjeuner",
"Pax": [
{
"Adult": 2,
"Child": [8],
"Rooms": [
{
"Id": 18,
"Name": "Chambre Deluxe Vue Mer",
"Price": 500,
"Quantity": 3,
"NotRefundable": false,
"OnRequest": false,
"StopReservation": false,
"CancellationPolicy": [
{ "Fees": 0, "Type": "PERCENT", "FromDate": "2026-12-15" }
]
}
]
}
]
}
]
}
}
],
"ErrorMessage": { "Code": null, "Description": null }
}
BookingCreation (pré-réservation)
PreBooking: true = pré-réservation seule. Le client rejoue ensuite la requête sans PreBooking pour confirmer — la passerelle tolère les deux.
Requête — POST /api/hotel/BookingCreation
{
"Credential": { "Login": "demo_os_login", "Password": "demo_os_password" },
"HotelBooking": {
"PreBooking": true,
"City": 0,
"Hotel": 1803258,
"CheckIn": "2027-01-15",
"CheckOut": "2027-01-20",
"Source": "12",
"Token": "rk_x9F2kQ8example",
"Rooms": [
{
"Id": 18,
"Boarding": "16",
"View": [],
"Supplement": [],
"Pax": {
"Adult": [
{ "Civility": "Mr", "Name": "TEST-A", "Surname": "TEST-B", "Holder": true }
],
"Child": [{ "Name": "TEST-C", "Surname": "TEST-B", "Age": 8 }]
}
}
]
}
}
Succès = BookingCreation non vide (Id, TotalPrice, Rooms, CancellationPolicy avec FromDate en d/m/Y). Échec = absence de BookingCreation + ErrorMessage { Code ≠ 200 }.
BookingDetail
Corps sans Credential :
Requête — POST /api/hotel/BookingDetail
{
"BookingReferenceId": "BPG-2026-000123",
"PaymentMode": "Limit"
}
Succès si Status.Code == 200 ; lire BookingDetail { BookingStatus, VoucherStatus, ConfirmationNumber, InvoiceNumber }. Les statuts annulés : Cancelled, CancellationInProgress, CancelPending, CancelledAndRefundAwaited.
BookingCancellation (simulation puis annulation)
Requête — POST /api/hotel/BookingCancellation (simulation)
{
"Credential": { "Login": "demo_os_login", "Password": "demo_os_password" },
"Booking": "BPG-2026-000123",
"PreCancelled": true
}
PreCancelled: true = simulation des frais, sans annulation réelle. Rejouez sans PreCancelled pour annuler. Erreur = BookingCancellation.ErrorMessage { Code ≠ 200 }.
Pièges à connaître
- HTTP 200 partout — lisez toujours
ErrorMessage.Code(etBookingCancellation.ErrorMessagepour l'annulation), jamais le seul code HTTP. Tokenà réinjecter tel quel — leTokende la réponseHotelSearchdoit revenir dansBookingCreation.Token, sans modification ni décodage.- Quota — dépassé, la
Descriptioncontient"Too many requests ... Retry after YYYY-MM-DD HH:MM:SS.": parsez-la pour votre backoff. - Disponibilité côté client — une chambre est vendable si
OnRequest != 1,StopSalesvide etStopReservation != 1. Boardingen chaîne — dansBookingCreation,Boardingest une chaîne ("16"), pas un entier.- Dates —
Y-m-ddansHotelSearch/BookingCreation, maisd/m/Ydans lesCancellationPolicy.FromDatedes réponses. Source— code du contrat direct Brave, à rejouer tel quel dansBookingCreation.Source.