Skip to main content

Content Catalog Overview

The Content API provides access to static and semi-static hotel catalog data. Use it to build search filters, display hotel information, and synchronize your local catalog.

What is Content API?

The Content API serves catalog data that doesn't change frequently:

  • Hotels – Hotel information, descriptions, amenities, media, and geo enrichment (canonical city, country, closest destinations, region)
  • Rooms – Room types, descriptions, images, occupancy details
  • Destinations – Cities, regions, airports with hierarchical structure
  • Boards – Meal plans (RO, BB, HB, FB, AI)
  • Categories – Hotel categories and classifications

Hotel responses include location enrichment when available: countryName, canonicalCityPlaceId, region, closestDestinations (e.g. city and region names), locationPath (breadcrumb like "Madrid, Community of Madrid, Spain"), and optional POI distances (airport, beach, train station).

How this fits with live booking

Use Content API for what to show in your UI and filters; use Booking API for prices and reservations. See Key concepts — Static vs transactional data for the canonical explanation.

Content Structure

Content Catalog
├── Hotels
│ ├── Basic info (name, description, location)
│ ├── Amenities, media, rooms
│ ├── Geo enrichment (canonical city, country, region, closest destinations)
│ └── Optional: POI distances, locationPath, imageBaseUrl
├── Rooms
│ ├── Description, images, occupancy, bed configuration
├── Destinations
│ ├── Hierarchical structure (country → region → city)
│ └── Geographic coordinates
├── Boards
│ └── Meal plan definitions
└── Categories
└── Hotel classifications

Hotel endpoints

  • POST /content/hotels/v1/hotels – List or get hotels by query (connection, codes, destination, etc.). Prefer scope over query for filters.
  • POST /content/hotels/v1/hotels/by-base-codes – Get hotel content by Bundleport base codes (e.g. for mapping/base-code–based UIs). Supports preferred content source and multiple sources per hotel.
  • POST /content/hotels/v1/hotels/filterFilter hotel codes by criteria (canonical city, country, categories, boards, nearby, etc.) with keyset pagination. Use before availability search to reduce payload.

Common use cases

1. Build search filters

Load destinations and boards (and optionally categories) from Content API on a schedule—e.g. nightly or weekly—and populate dropdowns. Keep this data separate from live availability: users still need a Booking API search for current price and inventory.

2. Display hotel information

For a hotel detail page, fetch hotel content by code (or base code) from Content API. Show descriptions, amenities, media, and enriched location fields. When the user picks dates, run availability with hotel codes from your cached catalog or from filter endpoints.

3. Pre-filter before availability

Use POST /content/hotels/v1/hotels/filter (or equivalent list endpoints) to obtain a bounded set of hotel codes for a destination or policy. Pass those codes in criteria.hotels on availability to reduce payload and latency. See Hotels.

4. Synchronize a local catalog

A local mirror lets you serve fast hotel pages and filters without hitting Content API on every HTTP request. Typical shape:

  1. Bootstrap – Run a full pass per connectionCode (or per environment) using list endpoints that return a continuation token. Persist token handling in one worker so retries stay idempotent.
  2. Normalize – Store stable primary keys (hotelCode, base codes, provider codes) and keep raw JSON or a subset of fields you render in the UI; attach updatedAt or audit fields when the API exposes them.
  3. Refresh – Schedule nightly or weekly full re-syncs for static-heavy objects (destinations, boards) and shorter TTLs for hotels if you show amenities or media that change often. Prefer incremental updates (only changed IDs) when you have audit or “since” APIs.
  4. Failure modes – If a page fails mid-run, resume from the last persisted token or restart with token: null and de-duplicate in your DB. Never assume tokens survive process restarts—treat them as ephemeral (see Pagination with Tokens below).

Optional implementation sketch:

// Initial sync - get all hotels (pseudo-code; adapt to your client)
let token = null;
let allHotels = [];

do {
const result = await getHotels({
query: { maxSize: 1000 },
token,
});

allHotels.push(...result.hotels.hotels);
token = result.hotels.token;
} while (token);

// Store in local database
await syncHotelsToDatabase(allHotels);

Filtering and Pagination

All content endpoints support:

  • Filtering by connection code - Get content for specific providers
  • Filtering by codes - Get specific hotels, rooms, destinations
  • Pagination - Use tokens for large result sets
  • Max size - Limit number of results per request

Example: Filtered query (prefer scope)

{
"scope": {
"connectionCode": "CONN_1",
"hotelCodes": ["12345", "67890"],
"maxSize": 50
},
"token": null
}

Use scope as the preferred field for filters; query is supported for backwards compatibility. When connectionCode is set, the provider is resolved automatically (use X-Environment: test or prod as needed).

Pagination with Tokens

Content API uses token-based pagination:

// First page
const page1 = await getHotels({
query: { maxSize: 100 },
token: null,
});

// Next page
const page2 = await getHotels({
query: { maxSize: 100 },
token: page1.hotels.token, // Use token from previous response
});

// Continue until token is null

Important:

  • Tokens are valid for 4 minutes
  • Tokens are tied to the original query criteria
  • If query changes, start with a new token (null)

Best Practices

1. Cache Content Data

// Cache destinations for 24 hours
const destinations = await cache.get('destinations', async () => {
return await getDestinations({ query: {} });
}, { ttl: 24 * 60 * 60 * 1000 }); // 24 hours

2. Incremental Sync

// Sync only changed content
const auditHistory = await getScopeAuditHistory({
contentType: 'hotel',
contentID: '12345',
limit: 100,
});

// Update only changed hotels
for (const record of auditHistory.auditRecords) {
if (record.action === 'updated') {
await syncHotel(record.contentID);
}
}

3. Batch Requests

// Get multiple hotels in one request
const hotels = await getHotels({
query: {
hotelCodes: ['12345', '67890', '11111'],
maxSize: 100,
},
});

Endpoints

EndpointDescription
HotelsList/get hotels; pagination with token
Hotels by base codesGet content by Bundleport base codes
Hotel filterFilter hotel codes (geo, categories, boards, etc.)
RoomsRoom types and details
DestinationsLocations and hierarchy
BoardsMeal plans
CategoriesHotel categories

Next Steps