> ## Documentation Index
> Fetch the complete documentation index at: https://docs.d-edge.com/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> This site documents the D-EDGE APIs for technology partners (web agencies, OTAs, PMS and RMS vendors, booking and CRM tools). It is written for developers integrating with hotels that use the D-EDGE platform.
> Seven APIs, grouped by domain. Connectivity: Channel Manager API (distribute a hotel's inventory to your channel and send bookings back). Pricing & Availability: Best Price API (best offers to highlight), Quotation API (all bookable offers for a stay), Daily Rates API (daily availability between two dates). Booking: Booking Engine API (a hotel's full direct booking funnel), Gift Shop API (gift vouchers from catalogue to payment). Guest Management: CRM API (guest profiles).
> Pick the API by the need: to display prices, use the Best Price API or the Daily Rates API; to quote a specific stay, use the Quotation API; to book, use the Booking Engine API; to sell gift vouchers, use the Gift Shop API; to manage guest profiles, use the CRM API; to receive hotel inventory and send bookings back as a distribution channel, use the Channel Manager API.
> Base URLs, hotel identifiers, and credentials are delivered by the D-EDGE partnership team during onboarding. Do not invent base URLs, endpoints, parameters, or example credentials that do not appear on these pages.
> Authentication differs per API: OAuth 1.0 for Best Price, Quotation, Daily Rates, and Booking Engine; an X-API-KEY header for Gift Shop; OAuth 2.0 client credentials for CRM; partner-defined credentials carried in the XML message for the Channel Manager API. Read each API's Authentication page before writing code.
> A mock environment returns realistic but fictitious data without credentials. The Postman and Insomnia collections on the API collections page target it by default. Use it for exploration and tests, never for production traffic.
> Use the official names exactly: D-EDGE, D-EDGE platform, Channel Manager API, partnership team. Do not use Back Office or Extranet.
> Each API has a Changelog page. Check it for the current behaviour before relying on an older answer. For questions these pages do not answer, direct the reader to the Contact us page.

# Hotels destination explorer

> Show a 'from' price for every hotel in a chain or destination

A destination explorer lets visitors browse every hotel in your portfolio with a "from" price per property. The Best Price Hotels (Arrivals) endpoint returns per-hotel pricing across your date window in a single call.

## Prerequisites

Before building a destination explorer, make sure you have:

* A working Best Price call. If not, follow the [Quick start](/best-price-api/get-started/quick-start.md) first.
* A group ID covering the hotels you want to display.
* A target date window (typically 30 to 90 days).

## How it works

The Hotels (Arrivals) endpoint returns one entry per hotel and requested strategy, with the best price found over your date window and the arrival date it applies to. With a single call and a single strategy in `behaviours` (`LowestLengthOfStay` when you send none), you get one "from" price per hotel in the group, with no aggregation on your side.

A hotel with no bookable offer in the window comes back with `status: NotAvailable`. Keep only the entries whose `status` is `Available` or `OnRequest`; a hotel without one has nothing to display.

## Build the explorer

> [!NOTE]
>
> The examples below assume the OAuth signing setup from the [Quick start](/best-price-api/get-started/quick-start.md).

### 1. Call Best Price Hotels (Arrivals) once

Send one request to `/BestPrice/Hotels/Arrivals` with your date range, group ID, and party. The response is an array with one entry per hotel.

```bash cURL theme={null}
curl --request POST \
  --url https://{apiBaseUrl}/Planning/2018A/BestPrice/Hotels/Arrivals \
  --header 'Authorization: OAuth ...' \
  --header 'Content-Type: application/json' \
  --data '{
    "beginDate": "2026-12-07",
    "endDate": "2027-01-05",
    "guests": {"adults": 2},
    "filter": {
      "ratePlan": {"groupId": <groupId>},
      "currency": "EUR"
    }
  }'
```

```javascript Node.js theme={null}
const url = "https://{apiBaseUrl}/Planning/2018A/BestPrice/Hotels/Arrivals";

const response = await fetch(url, {
  method: "POST",
  headers: { ...authHeaders, "Content-Type": "application/json" },
  body: JSON.stringify({
    beginDate: "2026-12-07",
    endDate: "2027-01-05",
    guests: { adults: 2 },
    filter: {
      ratePlan: { groupId: <groupId> },
      currency: "EUR",
    },
  }),
});
const data = await response.json();
```

```python Python theme={null}
response = session.post(
    "https://{apiBaseUrl}/Planning/2018A/BestPrice/Hotels/Arrivals",
    json={
        "beginDate": "2026-12-07",
        "endDate": "2027-01-05",
        "guests": {"adults": 2},
        "filter": {
            "ratePlan": {"groupId": <groupId>},
            "currency": "EUR",
        },
    },
)
data = response.json()
```

```php PHP theme={null}
$response = $client->post('Planning/2018A/BestPrice/Hotels/Arrivals', [
    'json' => [
        'beginDate' => '2026-12-07',
        'endDate'   => '2027-01-05',
        'guests'    => ['adults' => 2],
        'filter'    => [
            'ratePlan' => ['groupId' => <groupId>],
            'currency' => 'EUR',
        ],
    ],
]);
$data = json_decode($response->getBody(), true);
```

```csharp C# theme={null}
var request = new RestRequest("/BestPrice/Hotels/Arrivals", Method.Post);
request.AddJsonBody(new
{
    beginDate = "2026-12-07",
    endDate = "2027-01-05",
    guests = new { adults = 2 },
    filter = new
    {
        ratePlan = new { groupId = <groupId> },
        currency = "EUR"
    }
});

var response = await client.ExecuteAsync(request);
var data = JsonDocument.Parse(response.Content!).RootElement;
```

```java Java theme={null}
String body = mapper.writeValueAsString(Map.of(
    "beginDate", "2026-12-07",
    "endDate", "2027-01-05",
    "guests", Map.of("adults", 2),
    "filter", Map.of(
        "ratePlan", Map.of("groupId", <groupId>),
        "currency", "EUR"
    )
));

HttpPost request = new HttpPost("https://{apiBaseUrl}/Planning/2018A/BestPrice/Hotels/Arrivals");
request.setEntity(new StringEntity(body, "UTF-8"));
request.setHeader("Content-Type", "application/json");
consumer.sign(request);

JsonNode data;
try (CloseableHttpResponse response = client.execute(request)) {
    data = mapper.readTree(EntityUtils.toString(response.getEntity()));
}
```

### 2. Index the bookable entries by hotel

With a single strategy in `behaviours`, each hotel appears once, with its best `totalPrice` over the window and the `arrivalDate` it applies to. Keep the entries whose `status` is `Available` or `OnRequest`, and key them by `hotelId` to look up each hotel's "from" price and currency.

```javascript Node.js theme={null}
function indexByHotel(data) {
  const byHotel = new Map();
  for (const entry of data) {
    if (entry.status !== "Available" && entry.status !== "OnRequest") continue;
    byHotel.set(entry.hotelId, entry);
  }
  return byHotel;
}

const byHotel = indexByHotel(data);
```

```python Python theme={null}
def index_by_hotel(data):
    by_hotel = {}
    for entry in data:
        if entry["status"] not in ("Available", "OnRequest"):
            continue
        by_hotel[entry["hotelId"]] = entry
    return by_hotel

by_hotel = index_by_hotel(data)
```

```php PHP theme={null}
function indexByHotel(array $data): array {
    $byHotel = [];
    foreach ($data as $entry) {
        if (!in_array($entry['status'], ['Available', 'OnRequest'], true)) {
            continue;
        }
        $byHotel[$entry['hotelId']] = $entry;
    }
    return $byHotel;
}

$byHotel = indexByHotel($data);
```

```csharp C# theme={null}
var byHotel = data.EnumerateArray()
    .Where(d => d.GetProperty("status").GetString() is "Available" or "OnRequest")
    .ToDictionary(
        d => d.GetProperty("hotelId").GetInt32(),
        d => d
    );
```

```java Java theme={null}
Map<Integer, JsonNode> byHotel = new HashMap<>();
for (JsonNode entry : data) {
    String status = entry.get("status").asText();
    if (!status.equals("Available") && !status.equals("OnRequest")) continue;
    int hotelId = entry.get("hotelId").asInt();
    byHotel.put(hotelId, entry);
}
```

### 3. Render the property cards

Display each hotel with its "from" price, photo, location, and a CTA. For hotels with no bookable entry in the response, show a soft fallback rather than a hard "Sold out", since availability changes throughout the day.

```javascript Node.js theme={null}
hotels.forEach(hotel => {
  const cheapest = byHotel.get(hotel.id);
  renderHotelCard({
    hotelId: hotel.id,
    name: hotel.name,
    location: hotel.location,
    photo: hotel.photo,
    from: cheapest
      ? { price: cheapest.totalPrice, currency: cheapest.currency }
      : { fallback: "Check availability" },
  });
});
```

```python Python theme={null}
for hotel in hotels:
    cheapest = by_hotel.get(hotel["id"])
    render_hotel_card({
        "hotelId": hotel["id"],
        "name": hotel["name"],
        "location": hotel["location"],
        "photo": hotel["photo"],
        "from": (
            {"price": cheapest["totalPrice"], "currency": cheapest["currency"]}
            if cheapest else {"fallback": "Check availability"}
        ),
    })
```

```php PHP theme={null}
foreach ($hotels as $hotel) {
    $cheapest = $byHotel[$hotel['id']] ?? null;
    renderHotelCard([
        'hotelId'  => $hotel['id'],
        'name'     => $hotel['name'],
        'location' => $hotel['location'],
        'photo'    => $hotel['photo'],
        'from'     => $cheapest
            ? ['price' => $cheapest['totalPrice'], 'currency' => $cheapest['currency']]
            : ['fallback' => 'Check availability'],
    ]);
}
```

```csharp C# theme={null}
foreach (var hotel in hotels)
{
    var cheapest = byHotel.TryGetValue(hotel.Id, out var c) ? (JsonElement?)c : null;
    RenderHotelCard(new
    {
        hotelId = hotel.Id,
        name = hotel.Name,
        location = hotel.Location,
        photo = hotel.Photo,
        from = cheapest.HasValue
            ? (object)new
            {
                price = cheapest.Value.GetProperty("totalPrice").GetDecimal(),
                currency = cheapest.Value.GetProperty("currency").GetString()
            }
            : new { fallback = "Check availability" }
    });
}
```

```java Java theme={null}
for (Hotel hotel : hotels) {
    JsonNode cheapest = byHotel.get(hotel.id());
    Object from = cheapest != null
        ? Map.of(
            "price", cheapest.get("totalPrice").decimalValue(),
            "currency", cheapest.get("currency").asText()
        )
        : Map.of("fallback", "Check availability");
    renderHotelCard(Map.of(
        "hotelId", hotel.id(),
        "name", hotel.name(),
        "location", hotel.location(),
        "photo", hotel.photo(),
        "from", from
    ));
}
```

## Tips

* **Cache aggressively**. One call per (date range, party, group) combination. Easy cache key, big payoff for landing pages that get heavy browse traffic.
* **Use a tight date window**. 30 days is usually enough for an explorer page. A 90-day window costs more per call without changing the "from" price most of the time.
* **Consider `behaviours: ["EarliestAvailability"]`**. The default `LowestLengthOfStay` favours the shortest stay that clears the restrictions, and `CheapestStay` favours the lowest price. Switch to `EarliestAvailability` if your UI promises "earliest dates first": useful for last-minute or "next weekend" widgets. Keep a single value in `behaviours`: list several only to replace separate calls you would otherwise make, since each extra strategy slows the call. The single `behaviour` property is deprecated.
* **Scope by sub-region with `filter.hotels`**. If your group is large and your visitor is browsing a specific destination, filter the response to those hotels only with `filter.hotels.default: "Excluded"` and `exceptions: [hotelId, ...]`. Same allow-list pattern as the rooms filter.

## Related

> **[Reference](/best-price-api/build/reference/hotels-arrivals.md)**
>
> Full schema for the Hotels (Arrivals) endpoint.

> **[Best practices](/best-price-api/build/best-practices.md)**
>
> Caching, performance, and resilience patterns.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.