# Klook — Asian activities, attractions & experiences

> Search or browse Klook activities by keyword and/or destination, with category, price, date, instant-confirmation and sort filters. Every filter here was proved to change the result count against a same-run unfiltered control; filters Klook silently ignores are not offered.
> ReefAPI engine `klook` · 9 endpoints · clean JSON, no scraping or browsers to manage.

## How to call
- **Endpoint:** `POST https://api.reefapi.com/klook/v1/<action>` with a JSON body.
- **Auth:** header `x-api-key: <YOUR_REEFAPI_KEY>` — create one free (1,000 credits, no card): https://reefapi.com/signup
- **Response (every call):** `{ ok: boolean, data: ..., meta: { record_count, credits, ... }, error: { code, message } }` — branch on `ok`. Failed calls are free except verified SHEIN NOT_FOUND on product/detail and price (4 credits).
- **One key + one shared credit pool** across every ReefAPI API. Per-call credits are listed on each endpoint below.
- **Use it from an AI agent (MCP):** connect `https://api.reefapi.com/mcp` (remote streamable-http). Send the key as `Authorization: Bearer <key>`, or put it in the URL (`?key=<key>`) when the client has no header field, as ChatGPT does.

## Endpoints

### POST https://api.reefapi.com/klook/v1/activities/search — 2 credits
Search or browse Klook activities by keyword and/or destination, with category, price, date, instant-confirmation and sort filters. Every filter here was proved to change the result count against a same-run unfiltered control; filters Klook silently ignores are not offered.

**Parameters:**
- `query` (string, optional) — Free text — a place, an attraction, a product type. Klook's search is fuzzy and typo-tolerant, so a nonsense term can still return a handful of weak matches; the count returned is Klook's own.
- `destination_id` (integer, optional) — A city or country id AS RETURNED BY destinations/resolve in its search_location_id field. A country's own id is NOT accepted here (Klook offsets countries by 1000) and silently returns nothing, so take the value from the resolver rather than building it.
- `category` (enum, optional, default "all") — Klook's own top-level product tabs. [one of: all, tours, attractions, transport, hotels, more]
- `sort` (enum, optional, default "most_relevant") — Klook publishes exactly these five orderings. Any other value is accepted by the site and changes nothing, so it is rejected here instead. Note that these are Klook's RANKINGS, not strict sorts: asking for lowest price moves the cheapest results onto page one (the cheapest row on page one fell from 27.99 to 1.79 in a measured comparison) but promoted listings are still mixed in, so the page is about 63% strictly ascending. Sort the rows yourself if you need a guarantee. [one of: most_relevant, price, participants, publish_time, review_score]
- `price_min` (number, optional) — Lower bound, in the requested currency. Must be sent together with price_max.
- `price_max` (number, optional) — Upper bound, in the requested currency.
- `date` (string, optional) — Keep only activities bookable on this date (YYYY-MM-DD). With date_to it becomes a range.
- `date_to` (string, optional) — End of the availability range (YYYY-MM-DD). Ignored unless date is also given.
- `instant_confirmation` (boolean, optional) — Only activities Klook confirms immediately.
- `page` (integer, optional, default 1) — 20 results per page — the page size is fixed by Klook and a limit parameter is ignored. Klook stops counting broad queries at 1000 matches.
- `currency` (enum, optional, default "USD") — ISO currency the prices are returned in. Klook prices in HKD when nothing is asked for, so this is always sent; every price in the response repeats the code it belongs to. [one of: USD, HKD, SGD, JPY, KRW, TWD, THB, MYR, IDR, PHP, VND, CNY, AUD, NZD, GBP, EUR, CAD, INR, AED, CHF, SEK, DKK, NOK, PLN, CZK, HUF, RUB, BRL, MXN, ZAR, TRY, SAR, ILS, KHR, LAK, MMK, MOP, QAR, RON, EGP, LKR, BDT]
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** activities[] with id, title, url, category, city, coordinates, price and struck price in the requested currency, rating, review count and tags; plus total, page and the categories/sorts Klook offers for this query.

**Example request body:**
```json
{
  "destination_id": 28,
  "category": "attractions",
  "currency": "USD"
}
```

### POST https://api.reefapi.com/klook/v1/activities/list — 2 credits
Destination browse in 50-result pages — the bulk-listing shape for walking a city's or a country's whole catalogue. Fewer filters than activities/search (Klook's list endpoint ignores category and sort), but 2.5x the rows per call.

**Parameters:**
- `query` (string, optional) — Free text. Optional — omit it to browse a destination.
- `city_id` (array, optional) — One or more Klook city ids (from destinations/resolve). Plain city ids here — no offset.
- `country_id` (array, optional) — One or more Klook country ids (from destinations/resolve). Plain country ids here.
- `price_min` (number, optional) — Lower bound in the requested currency.
- `price_max` (number, optional) — Upper bound in the requested currency.
- `instant_confirmation` (boolean, optional) — Only activities Klook confirms immediately.
- `page` (integer, optional, default 1) — 50 results per page, fixed by Klook.
- `currency` (enum, optional, default "USD") — ISO currency the prices are returned in. Klook prices in HKD when nothing is asked for, so this is always sent; every price in the response repeats the code it belongs to. [one of: USD, HKD, SGD, JPY, KRW, TWD, THB, MYR, IDR, PHP, VND, CNY, AUD, NZD, GBP, EUR, CAD, INR, AED, CHF, SEK, DKK, NOK, PLN, CZK, HUF, RUB, BRL, MXN, ZAR, TRY, SAR, ILS, KHR, LAK, MMK, MOP, QAR, RON, EGP, LKR, BDT]
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** activities[] with id, title, url, images, price, rating, review count and tags; plus total and page.

**Example request body:**
```json
{
  "city_id": [
    28
  ],
  "currency": "USD"
}
```

### POST https://api.reefapi.com/klook/v1/activity/detail — 2 credits
The full published record for one activity: description, highlights, what's included, images, address and coordinates, category path, rating, review count and the price span across its packages.

**Parameters:**
- `activity_id` (integer, required) — Klook activity id — the number in an activity URL (/activity/93901-…), or the activity_id from search.
- `currency` (enum, optional, default "USD") — ISO currency the prices are returned in. Klook prices in HKD when nothing is asked for, so this is always sent; every price in the response repeats the code it belongs to. [one of: USD, HKD, SGD, JPY, KRW, TWD, THB, MYR, IDR, PHP, VND, CNY, AUD, NZD, GBP, EUR, CAD, INR, AED, CHF, SEK, DKK, NOK, PLN, CZK, HUF, RUB, BRL, MXN, ZAR, TRY, SAR, ILS, KHR, LAK, MMK, MOP, QAR, RON, EGP, LKR, BDT]
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** activity{} with title, subtitle, summary, highlights[], what_we_love, insider_tips, images[], address, coordinates, place_id, category_path[], rating, review_count, price, strike_price, price_range and default_package_id; plus requested_activity_id and a redirected flag, because Klook sometimes answers with a superseded listing's replacement rather than the id you asked for. Cancellation terms are published per package, not per activity — use activity/packages for those.

**Example request body:**
```json
{
  "activity_id": 141,
  "currency": "USD"
}
```

### POST https://api.reefapi.com/klook/v1/activity/packages — 2 credits
Every bookable package (option) of one activity with its OWN price, cancellation policy, confirmation type, voucher type and party-size limits — plus the dates Klook currently publishes as available. Klook prices packages independently: the same attraction can run from 46 to 503 in one currency, so a headline price is not the price.

**Parameters:**
- `activity_id` (integer, required) — Klook activity id.
- `currency` (enum, optional, default "USD") — ISO currency the prices are returned in. Klook prices in HKD when nothing is asked for, so this is always sent; every price in the response repeats the code it belongs to. [one of: USD, HKD, SGD, JPY, KRW, TWD, THB, MYR, IDR, PHP, VND, CNY, AUD, NZD, GBP, EUR, CAD, INR, AED, CHF, SEK, DKK, NOK, PLN, CZK, HUF, RUB, BRL, MXN, ZAR, TRY, SAR, ILS, KHR, LAK, MMK, MOP, QAR, RON, EGP, LKR, BDT]
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** packages[] each with package_id, name, price, strike_price, cancellation_policy, confirmation_type, ticket_type, min/max participants and stock; available_dates[]; is_open_dated.

**Example request body:**
```json
{
  "activity_id": 93901,
  "currency": "USD"
}
```

### POST https://api.reefapi.com/klook/v1/activities/batch — 1 credit
Price, rating, coordinates, package count and availability for up to 50 activities in ONE upstream call. This is the efficient shape for refreshing a watchlist — 50 ids cost one call instead of 50.

**Parameters:**
- `activity_id` (array, required) — Up to 50 Klook activity ids. Ids Klook does not publish are reported in missing_ids rather than silently dropped.
- `currency` (enum, optional, default "USD") — ISO currency the prices are returned in. Klook prices in HKD when nothing is asked for, so this is always sent; every price in the response repeats the code it belongs to. [one of: USD, HKD, SGD, JPY, KRW, TWD, THB, MYR, IDR, PHP, VND, CNY, AUD, NZD, GBP, EUR, CAD, INR, AED, CHF, SEK, DKK, NOK, PLN, CZK, HUF, RUB, BRL, MXN, ZAR, TRY, SAR, ILS, KHR, LAK, MMK, MOP, QAR, RON, EGP, LKR, BDT]
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** activities[] with id, title, url, price, struck price, price range, rating, review count, coordinates, city/country, package_count and next_available_at; plus requested/found counts and missing_ids[].

**Example request body:**
```json
{
  "activity_id": [
    141,
    93901,
    1552
  ],
  "currency": "USD"
}
```

### POST https://api.reefapi.com/klook/v1/activity/reviews — 1 credit
Traveller reviews for one activity, newest first, with rating, text, photos, the package the reviewer booked and any operator reply.

**Parameters:**
- `activity_id` (integer, required) — Klook activity id.
- `page` (integer, optional, default 1) — Klook serves at most 2,000 reviews per activity even when the activity has far more; a page past that boundary returns an empty list.
- `limit` (integer, optional, default 20) — Reviews per page (Klook honours up to 100).
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** reviews[] with review_id, author, rating, date, text, images, package_name and reply; plus total, rating and page.

**Example request body:**
```json
{
  "activity_id": 141
}
```

### POST https://api.reefapi.com/klook/v1/destinations/resolve — 1 credit
Turn a typed place name into the ids the other actions need. Returns cities and countries, each with a search_location_id already in the form activities/search expects — Klook offsets country ids by 1000 there and answers a bare country id with an empty result, so this is the intended way in.

**Parameters:**
- `query` (string, required) — A place as a traveller would type it.
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** cities[] and countries[] with id, name, seo slug, url and search_location_id; plus activities[] Klook suggests for the term.

**Example request body:**
```json
{
  "query": "tokyo"
}
```

### POST https://api.reefapi.com/klook/v1/destinations/browse — 1 credit
Klook's own destination directory — world regions with their featured cities, and every country Klook sells in, each already carrying the id activities/search needs. The starting point when you have no place name to resolve. Ask for include_all_cities to get the complete 1,400-plus city list instead of the featured ones.

**Parameters:**
- `include_all_cities` (boolean, optional, default false) — Include every city Klook publishes (about 1,440) rather than only the featured ones. Adds roughly 200 KB to the response.
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** regions[] each with cities[] (city_id, name, country_id, url, search_location_id), countries[] with search_location_id, counts, and all_cities[] when asked for.

**Example request body:**
```json
{
  "include_all_cities": false
}
```

### POST https://api.reefapi.com/klook/v1/categories — 1 credit
The category vocabulary: Klook's top-level product tabs (the values activities/search accepts) and the second-level activity categories with their ids and links.

**Parameters:**
- `language` (enum, optional, default "en-US") — Content language. Klook's catalogue differs slightly per language — the same search returns 1,412 results in English and 1,319 in Japanese — so the row count is language-specific, not an error. [one of: en, en-US, en-GB, en-AU, en-CA, en-HK, en-IN, en-MY, en-NZ, en-PH, en-SG, en-AE, de, es, fr, id, it, ja, ko, ru, th, vi, zh-CN, zh-HK, zh-TW, ms-MY, pl, cs, sk, bg, nl, ca, pt-PT, pt-BR, da, sv, fi, nb, el, hu, tl, hi, ta, si, bn, ro]

**Returns:** tabs[] (value, label, description) and categories[] (id, name, url).

**Example request body:**
```json
{
  "language": "en-US"
}
```

## At scale
- **Volume:** 5M+ requests a day, measured at 60 requests a second across the fleet with no
  central bottleneck. Per-key limits are raised for high-volume accounts; volume pricing on request.
- **Missing a source:** tell us a site we do not cover and it becomes an engine. A customer asked
  for bestprice.gr on 21 Sep 2026 and it was in the catalog on 22 Sep.
- **Support:** 2 minute median time from a question in the live chat to the first answer. Setup
  help included, no support tier to buy.
- **One key, one credit pool** across every API. No per-site plans, no separate subscriptions.

## More
- Try it live, no code: https://reefapi.com/playground?engine=klook
- Human docs page: https://reefapi.com/docs/klook
- Overview page: https://reefapi.com/klook-api
- Every ReefAPI API in one file (for your AI): https://reefapi.com/llms-full.txt
