Skip to content
Docs

Core concepts

The ideas every endpoint shares: property identifiers, markets and currencies, how a price is broken down, provenance, batch jobs and request IDs.

Every endpoint returns a different source, but they share a handful of ideas. Read this page once and the reference pages will read faster.

Property identifiers

Each source names a hotel its own way. Resolve a property once, store its identifiers next to your own hotel record, and reuse them on every later call. Identifiers are stable, so there is no reason to search again before each price request.

SourceIdentifierWhere it comes from
Google Hotels
token
Booking.com
pagename (URL slug)
POST /v1/ota/booking/search
Expedia / Hotels.com
numeric property id, per site
POST /v1/ota/expedia/search, /v1/ota/hotels/search
Agoda
Agoda hotel id
POST /v1/ota/agoda/search
Tripadvisor
location_id
the number after -d in the property URL
Airbnb
listing_id
airbnb.com/rooms/<id>, or Airbnb search
Vrbo
property_id
Vrbo search, or resolved from a listing id

Expedia and Hotels.com ids only match for newer properties, so resolve each site separately. When a name is ambiguous, confirm the match by address with POST /v1/hotels/resolve (see Identify a property).

Markets and currencies

A market is the point of sale a price is collected for, such as US, GB or AU. It decides the country the source sees and the default tax basis. currency sets the currency of the returned prices. GET /v1/markets lists the configured markets with their currency and whether their published rates include tax, and it is free.

Keep the market constant

The same room can be shown differently by market (some lead with the total, others with the nightly price). Compare prices collected for the same market and currency.

How a price is broken down

Hotel prices keep their parts apart, so you can compare like with like across markets that show tax differently. A calendar row carries:

FieldMeaning
rate_base
Room-only price before tax and mandatory fees.
tax
Taxes on the stay.
fees
Mandatory fees.
rate_before_taxes_with_fees
rate_base + fees, the basis many SERP APIs call extracted_price_before_taxes.
rate_total
All-in price including tax and fees.
rate
The figure to store for the market: rate_total when rates_include_tax is true, otherwise the pre-tax base.
min_length_of_stay
Set when a night only sells with a longer stay; rate is then the per-night figure from that stay.
One calendar row (trimmed)
{
  "token": "ChUIoben2Mv6-CYaCi9tLzA3czVwbjQQAQ",
  "stay_date": "2026-11-17",
  "rate": 168.9,
  "rate_base": 168.9,
  "rate_before_taxes_with_fees": 174.9,
  "rate_total": 199.0,
  "tax": 24.1,
  "fees": 6.0,
  "currency": "USD",
  "market": "US",
  "rates_include_tax": false,
  "los": 1,
  "min_length_of_stay": null,
  "provenance": {
    "observation_id": "rateobs_…",
    "collection_id": "ratecol_…",
    "observed_at": "2026-11-01T06:00:12Z",
    "source": "google_hotels_calendar",
    "source_kind": "calendar",
    "requested_currency": "USD",
    "returned_currency": "USD",
    "price_basis": "room_base_before_taxes_and_fees",
    "derivation": "normalized_upstream"
  }
}

Other sources follow their own conventions, and the API does not invent missing parts. Airbnb's nightly rate is all-in before taxes, so it depends on the length of the stay. Vrbo returns its own total without an itemized fee breakdown. Each guide notes what its source provides.

Provenance

Every calendar row carries a provenance object that records where, when and how the price was observed. Store it with the price and you can always trace a number in your warehouse back to its collection.

FieldWhat it tells you
observed_at
UTC time of the observation.
source
The upstream source, for example google_hotels_calendar.
observation_id
Deterministic id of this observation (rateobs_…).
collection_id
Shared by every price from one upstream fetch (ratecol_…).
requested_currency
With returned_currency, shows whether a conversion was needed.
price_basis
What the price represents, for example room_base_before_taxes_and_fees.
derivation
How the figure was produced; derived_fields lists fields computed by ScraperCompany rather than read from the source.

Live and stored rates

Price endpoints collect from the source when you call them, so a response reflects what the source showed at observed_at. To read observations that were already collected without calling a source again, use GET /v1/rates/stored, which returns freshness metadata and costs nothing.

Batch jobs and idempotency

For many properties at once, submit a job instead of looping. POST /v1/jobs takes up to 50 calendar items, stores the job before it answers and keeps running across API restarts. Poll GET /v1/jobs/{job_id}, or pass a callback_url and receive a signed webhook when the job finishes.

Every submission needs an Idempotency-Key header. Resending the same key with the same body returns the original job, so a retry after a timeout never starts a second run. The same key with a different body returns 409. See Monitor a comp set.

Request IDs

Every response carries an x-request-id header (req_…). It matches the id in your request history (GET /v1/requests) and the request_id on billing ledger entries. Include it when you contact support.

What gets billed

Each operation has a fixed credit cost per successful call, listed on its reference page. A few scale with the work: per page of results, per priced night, or per calendar surcharge. Failed requests (any 4xx or 5xx) and empty results cost nothing. Metered responses report the charge in x-credits-charged and the balance in x-credits-remaining. See Credits & billing.

Questions about this page?

Send the page link and your question, and the team will answer.

Email support