OS-Travel compatible gateway (Octasoft)

This gateway reproduces the Octasoft OS-Travel API (V1 and V2): same methods, same field names, same formats. If your system already talks to MyGo, Tunisia Beds or Mouradi, it talks to the gateway unmodified.

Transport

  • URL — POST {base}/api/hotel/<Method> (e.g. {base}/api/hotel/HotelSearch).
  • Content-Type — application/json (V2) and application/x-www-form-urlencoded (V1 sends raw JSON without an explicit header: both are accepted).
  • Response — always HTTP 200, even on business errors: V1/V2 clients only parse 200.
  • Authentication — Credential { Login, Password } in every request (except BookingDetail).

Error envelope — still HTTP 200

{
  "ErrorMessage": {
    "Code": 401,
    "Description": "Invalid credentials."
  }
}

Methods

MethodBrave gateway equivalentDescription
ListCountryGET /v1/{code}/reference/countriesCountries
ListCityGET /v1/{code}/reference/citiesCities
ListBoardingGET /v1/{code}/reference/boardingsBoard types
ListCategorieGET /v1/{code}/reference/categoriesHotel categories
ListCurrencyGET /v1/{code}/reference/currenciesCurrencies
ListHotelGET /v1/{code}/hotelsExposed hotel catalogue
HotelDetailGET /v1/{code}/hotels/{id}Editorial sheet
HotelSearchPOST /v1/{code}/availabilitySearch by city or hotel list
BookingCreation (PreBooking)POST /v1/{code}/checkrate + POST /v1/{code}/bookingsPre-booking then confirmation
BookingListGET /v1/{code}/bookingsBooking list
BookingDetailGET /v1/{code}/bookings/{ref}Detail and status
BookingCancellation (PreCancelled)POST /v1/{code}/bookings/{ref}/cancelSimulation (PreCancelled) then cancellation

Full examples

HotelSearch

Dates in Y-m-d format. City or Hotels (id list). Rooms exists in two dialects, both accepted:

  • V1 — strings: { "Adult": "2", "Child": ["3", "8"] } (Child key absent when no children)
  • V2 — integers: { "Adult": 2, "Child": [3, 8] }

Request — 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] }]
  }
}

The response is an array HotelSearch, one entry per source (direct contract), with the Token (= our rateKey) to keep:

Response — 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 (pre-booking)

PreBooking: true = pre-booking only. The client then replays the request without PreBooking to confirm — the gateway accepts both.

Request — 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 }]
        }
      }
    ]
  }
}

Success = non-empty BookingCreation (Id, TotalPrice, Rooms, CancellationPolicy with FromDate in d/m/Y). Failure = absence of BookingCreation + ErrorMessage { Code ≠ 200 }.

BookingDetail

Body without Credential:

Request — POST /api/hotel/BookingDetail

{
  "BookingReferenceId": "BPG-2026-000123",
  "PaymentMode": "Limit"
}

Success when Status.Code == 200; read BookingDetail { BookingStatus, VoucherStatus, ConfirmationNumber, InvoiceNumber }. Cancelled statuses: Cancelled, CancellationInProgress, CancelPending, CancelledAndRefundAwaited.

BookingCancellation (simulation then cancellation)

Request — POST /api/hotel/BookingCancellation (simulation)

{
  "Credential": { "Login": "demo_os_login", "Password": "demo_os_password" },
  "Booking": "BPG-2026-000123",
  "PreCancelled": true
}

PreCancelled: true = fee simulation, without really cancelling. Replay without PreCancelled to cancel. Error = BookingCancellation.ErrorMessage { Code ≠ 200 }.

Pitfalls

  • HTTP 200 everywhere — always read ErrorMessage.Code (and BookingCancellation.ErrorMessage for cancellations), never the HTTP code alone.
  • Replay the Token as-is — the Token from the HotelSearch response must come back in BookingCreation.Token, unmodified and undecoded.
  • Quota — when exceeded, Description contains "Too many requests ... Retry after YYYY-MM-DD HH:MM:SS.": parse it for your backoff.
  • Client-side availability — a room is sellable when OnRequest != 1, StopSales empty and StopReservation != 1.
  • Boarding as a string — in BookingCreation, Boarding is a string ("16"), not an integer.
  • Dates — Y-m-d in HotelSearch/BookingCreation, but d/m/Y in response CancellationPolicy.FromDate.
  • Source — Brave direct contract code, replayed as-is in BookingCreation.Source.

Was this page helpful?