# Agoda\_hotel\_room (`minimal_junglefowl/agoda-hotel-room`) Actor

- **URL**: https://apify.com/minimal\_junglefowl/agoda-hotel-room.md
- **Developed by:** [39\_Đinh Nguyễn Nhật Lâm](https://apify.com/minimal_junglefowl) (community)
- **Categories:** Automation, Agents
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per usage

This Actor is paid per platform usage. The Actor is free to use, and you only pay for the Apify platform usage, which gets cheaper the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-usage

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js/docs.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python/docs.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/integrations/mcp.md).

If your project is in a different language, use the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).


# README

## Agoda Hotel Scraper

Trích xuất dữ liệu khách sạn có cấu trúc từ Agoda: thông tin khách sạn, điểm review theo hạng mục,
loại phòng, tiện nghi, tọa độ và hình ảnh — bằng cách gọi JSON API nội bộ của Agoda thay vì parse HTML,
giúp bền vững hơn khi giao diện thay đổi.

> Actor này lấy cảm hứng từ `bovi/agoda-scraper`. Đây là bản tự xây để học/tùy biến.

---

### Kiến trúc & vai trò của Apify

Actor gồm 2 phần tách biệt: **hạ tầng (Apify)** và **logic nghiệp vụ (code trong `src/`)**.
Apify không "biết" gì về Agoda — nó chỉ là nơi chạy code, cấp proxy và lưu kết quả. Toàn bộ
việc gọi đúng endpoint, dịch dữ liệu, xử lý lỗi là code tự viết.

```mermaid
flowchart LR
    subgraph User["Người dùng"]
        U1[Nhập input trên Console/API]
        U2[Xem / tải Dataset]
    end

    subgraph Apify["Apify Platform — hạ tầng"]
        direction TB
        A1[Console / API]
        A2["Build từ GitHub<br/>(Dockerfile + .actor/actor.json)"]
        A3[Container chạy Actor]
        A4[Proxy Residential]
        A5[("Dataset (lưu trữ + export)")]
    end

    subgraph Actor["Container Actor — code tự viết (src/)"]
        direction TB
        M["main.py<br/>điều phối input → output"]
        AG["agoda.py<br/>logic gọi & parse Agoda"]
    end

    subgraph AgodaSite["agoda.com — bên thứ 3"]
        S[Suggest API]
        G["GraphQL<br/>propertyDetailsSearch"]
        SD[GetSecondaryData]
    end

    U1 --> A1 --> A3
    A2 -. build image .-> A3
    A3 --> M --> AG
    AG <-->|qua proxy| A4
    A4 <--> S
    A4 <--> G
    A4 <--> SD
    M -->|push_data| A5
    A5 --> U2
````

**Bên trong 1 lần lấy khách sạn** (`fetch_hotel`) — gọi song song 2 nguồn rồi gộp lại:

```mermaid
sequenceDiagram
    participant Main as main.py
    participant Client as AgodaClient (agoda.py)
    participant Agoda as agoda.com

    Main->>Client: resolve_search("Hilton Saigon")
    Client->>Agoda: GET GetUnifiedSuggestResult
    Agoda-->>Client: danh sách ứng viên + hotelId
    Client-->>Main: hotelId = 47843559

    Main->>Client: fetch_hotel(47843559)
    par Nội dung chính
        Client->>Agoda: POST /graphql/property (propertyDetailsSearch)
        Agoda-->>Client: tên, địa chỉ, review, tiện nghi, ảnh...
    and Phòng & lân cận
        Client->>Agoda: GET GetSecondaryData
        Agoda-->>Client: rooms, nearby, highlights, giờ check-in/out
    end
    Client-->>Main: record đã gộp + chuẩn hoá (40 field)
    Main->>Main: push_data(record) → Dataset
```

#### Ai làm gì

| Thành phần | Do ai cung cấp | Vai trò |
|---|---|---|
| Nơi chạy actor (container, trigger qua Console/API/lịch chạy) | **Apify** | Hạ tầng chạy code — không cần tự dựng server |
| `Actor.get_input()` / `push_data()` / proxy xoay IP / log | **Apify SDK** (`apify` package) | Cầu nối giữa code Python và nền tảng: đọc input form, ghi Dataset, cấp proxy |
| Build image từ GitHub, versioning | **Apify** | Tự động build lại mỗi khi bấm Build (đọc `Dockerfile` + `.actor/actor.json`) |
| Kho lưu kết quả, export JSON/CSV/Excel | **Apify** (Dataset) | Không cần tự dựng database |
| Biết gọi đúng endpoint nào của Agoda, header nào bắt buộc | **Code tự viết** (`src/agoda.py`) | "Não" của actor — Apify hoàn toàn không biết gì về Agoda |
| Parse, chuẩn hoá, dịch dữ liệu theo ngôn ngữ | **Code tự viết** (`src/agoda.py`) | Gộp 3 nguồn Agoda thành 1 record 40 field |
| Đọc input, điều phối vòng lặp, xử lý lỗi từng khách sạn | **Code tự viết** (`src/main.py`) | Cầu nối giữa input Apify và logic Agoda |

Nói ngắn gọn: nếu thay Agoda bằng 1 trang web khác, phần **Apify không đổi gì cả** — chỉ cần
viết lại `src/agoda.py`.

***

### Tính năng

- Nhận **từ khóa tìm kiếm** (tên khách sạn cụ thể), **URL trang khách sạn**, hoặc **tên vùng/thành
  phố** (vd "Hồ Chí Minh") làm đầu vào — với vùng, actor tự liệt kê hàng loạt khách sạn trong đó.
- Trả về metadata khách sạn: tên, địa chỉ, hạng sao, điểm review, số review, tiện nghi, phòng, tọa độ, ảnh.
- Hỗ trợ **proxy** (khuyên dùng Apify Residential) và **giới hạn tần suất** để giảm nguy cơ bị chặn.
- Bắt lỗi theo từng khách sạn: một lỗi không làm hỏng cả run.
- Có `warnings` để báo chất lượng parse (rỗng nếu bình thường).

***

### Input

| Field | Kiểu | Mô tả |
|-------|------|-------|
| `searchTerms` | array (string) | Tên khách sạn hoặc điểm đến. Hiệu quả nhất với tên cụ thể (vd `"The Peninsula Bangkok"`). |
| `propertyUrls` | array (string) | URL trang khách sạn Agoda. Actor tự tách `hotelId`. **Nếu URL có sẵn `checkIn`/`checkOut` (hoặc `los`)/`adults`/`rooms`, actor tự lấy GIÁ THỰC TẾ** cho khách sạn đó — không cần điền `checkIn` ở dưới. |
| `hotelIds` | array (string/int) | ID khách sạn Agoda nếu đã biết (vd `10715`). |
| `locations` | array (string) | Tên vùng/thành phố (vd `"Hồ Chí Minh"`) **hoặc** dán trực tiếp link trang tìm kiếm Agoda (vd `https://www.agoda.com/vi-vn/search?city=13170&checkIn=2026-08-01&checkOut=2026-08-03&adults=2&rooms=1`) — link được ưu tiên xử lý vì đã có sẵn `cityId`, nhanh hơn. **Nếu link có ngày/số khách, TẤT CẢ khách sạn tìm được trong vùng đó dùng chung tiêu chí này để lấy giá thực tế.** Giới hạn bởi `maxItemsPerLocation`. |
| `maxItemsPerLocation` | integer | Số khách sạn tối đa lấy cho **mỗi** vùng trong `locations`. `0` = không giới hạn (có trần an toàn nội bộ ~2000). Mặc định `50`; ví dụ dùng thực tế: `200`. |
| `checkIn` | string | Ngày check-in mặc định (`YYYY-MM-DD`, chọn qua date-picker trên Console), dùng cho khách sạn **không** có sẵn ngày từ URL (vd `hotelIds`, `searchTerms`, hoặc `locations` gõ tên thường). Bỏ trống = không lấy giá (nhanh hơn). |
| `checkOut` | string | Ngày check-out (`YYYY-MM-DD`, date-picker). Nếu bỏ trống, tự tính từ `checkIn` + `lengthOfStay`. |
| `lengthOfStay` | integer | Số đêm ở lại — chỉ dùng khi **không** cấp `checkOut`. Mặc định `1`. |
| `adults` / `rooms` | integer | Số người lớn / số phòng, dùng cùng `checkIn`. Mặc định `2` / `1`. |
| `language` | string | Ngôn ngữ kết quả: `en-us` (mặc định), `vi-vn`, `th-th`, `ko-kr`, `ja-jp`, `zh-cn`, `id-id`. Ảnh hưởng tên phòng, tiện nghi, mô tả, địa điểm lân cận, **và cả `category_scores`/`score_distribution`**. |
| `maxItems` | integer | Số bản ghi tối đa. `0` = không giới hạn. Mặc định `0`. |
| `requestDelay` | integer | Số giây chờ giữa các request (0–30). Mặc định `2`. |
| `proxyConfiguration` | object | Cấu hình proxy. Mặc định Apify Residential. |

> ⚠️ Giá hiện chỉ hỗ trợ tiền tệ **VND**. Mỗi khách sạn có `checkIn` (từ URL hoặc input) sẽ tốn
> thêm 1 request gọi giá (`room-grid`), nên chạy chậm hơn khi bật tính năng này ở quy mô lớn.

#### Ví dụ input — tìm 1 khách sạn cụ thể

```json
{
  "searchTerms": ["The Peninsula Bangkok"],
  "propertyUrls": [],
  "maxItems": 0,
  "requestDelay": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

#### Ví dụ input — tìm 200 khách sạn theo vùng

Cách 1 — gõ tên vùng:

```json
{
  "locations": ["Hồ Chí Minh"],
  "maxItemsPerLocation": 200,
  "language": "vi-vn",
  "requestDelay": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

Cách 2 — dán link tìm kiếm Agoda (copy từ trình duyệt sau khi tự tìm trên agoda.com, nhanh hơn
vì đã có sẵn `cityId`, không tốn thêm request đổi tên → id):

```json
{
  "locations": ["https://www.agoda.com/vi-vn/search?city=13170&locale=vi-vn&textToSearch=H%E1%BB%93+Ch%C3%AD+Minh"],
  "maxItemsPerLocation": 200,
  "language": "vi-vn"
}
```

#### Ví dụ input — lấy kèm giá thực tế (không còn `null`)

Cách đơn giản nhất: dán URL đã có sẵn ngày/số khách (copy thẳng từ thanh địa chỉ trình duyệt
sau khi bạn tự chọn ngày trên agoda.com) — actor tự đọc `checkIn`/`checkOut`/`adults`/`rooms`
từ URL, không cần khai báo lại:

```json
{
  "propertyUrls": [
    "https://www.agoda.com/hilton-saigon/hotel/ho-chi-minh-city-vn.html?checkIn=2026-09-10&checkOut=2026-09-12&adults=2&rooms=1"
  ],
  "language": "vi-vn"
}
```

Hoặc dùng `checkIn`/`checkOut` (hoặc `lengthOfStay`)/`adults`/`rooms` ở input gốc — áp dụng cho
mọi khách sạn không có sẵn ngày riêng (kể cả `hotelIds`, `searchTerms`, hoặc `locations` gõ tên
thường):

```json
{
  "locations": ["Hồ Chí Minh"],
  "maxItemsPerLocation": 20,
  "checkIn": "2026-09-10",
  "checkOut": "2026-09-12",
  "adults": 2,
  "rooms": 1,
  "language": "vi-vn"
}
```

> Không chọn `checkOut`? Actor tự tính bằng `checkIn` + `lengthOfStay` (mặc định `1` đêm) như
> trước đây.

> ⚠️ Mỗi khách sạn tìm theo vùng vẫn lấy **đầy đủ 40 field** (2–3 request/khách sạn, thêm 1 nếu
> có lấy giá) nên chạy chậm hơn nhiều so với danh sách rút gọn: 200 khách sạn × ~3 request ×
> `requestDelay` giây có thể mất hàng chục phút. Muốn nhanh hơn thì giảm `maxItemsPerLocation`
> hoặc giảm `requestDelay` (đánh đổi với rủi ro bị chặn).

***

### Output (mỗi bản ghi vào Dataset)

| Field | Mô tả |
|-------|-------|
| `hotel_id` / `hotel_name` | Định danh & tên |
| `accommodation_type` | Loại hình (Hotel, Apartment...) |
| `address` / `city` / `country` / `area_name` | Vị trí |
| `location_highlight` | Nhấn mạnh vị trí (vd "trong nội thành") |
| `star_rating` | Hạng sao (1–5) |
| `review_score` / `review_count` / `review_text` | Điểm, số review, nhãn đã dịch theo `language` (vd "Trên cả tuyệt vời") |
| `category_scores` | Điểm theo hạng mục — **nhãn đã dịch theo `language`** (vd `{"Độ sạch sẽ": 9.6, "Vị trí": 9.7, ...}`), lấy trực tiếp từ Agoda nên đúng cho mọi ngôn ngữ hỗ trợ |
| `score_distribution` | Phân bố review theo mức — **nhãn đã dịch theo `language`** (vd `{"9+ Hiếm Có": 380, ...}`) |
| `awards` | Giải thưởng (nếu có) |
| `price` / `currency` | Giá phòng rẻ nhất/đêm toàn khách sạn (hiện chỉ hỗ trợ VND) — **chỉ có giá trị khi cấp `checkIn`** (qua URL hoặc input); không thì `null`. |
| `rooms_available` | Còn phòng cho ngày đã chọn hay không (`true`/`false`/`null`). |
| `offer_count` | Tổng số gói giá (offer) tìm được trên mọi loại phòng. |
| `check_in` / `check_out` | Ngày dùng để tính giá (đã chuẩn hoá `YYYY-MM-DD`, `null` nếu không lấy giá). |
| `room_types` | Danh sách tên loại phòng |
| `rooms` | Chi tiết từng phòng — xem bảng riêng bên dưới. |
| `amenities` / `amenity_groups` | Tiện nghi (phẳng & theo nhóm) |
| `highlights` | Điểm nổi bật của khách sạn |
| `nearby_attractions` | Điểm tham quan gần (kèm khoảng cách) — nguồn không có toạ độ riêng từng điểm |
| `nearby_essentials` | Sân bay/giao thông/tiện ích: category, name, distance\_km, distance\_text, coordinates (toạ độ riêng của điểm đó, dạng `"lat,lng"`) |
| `check_in_time` / `check_in_until` | Giờ bắt đầu nhận phòng / giờ nhận phòng muộn nhất (vd `14:00` / `23:59`) |
| `check_out_time` / `reception_open_until` | Giờ trả phòng / giờ quầy tiếp tân đóng cửa (vd `12:00` / `05:30`) — không phải khách sạn nào cũng có đủ 4 mục này, thiếu thì để `null` |
| `description` | Mô tả đầy đủ (HTML) |
| `image_url` / `image_count` / `all_images` | Ảnh |
| `coordinates` | Toạ độ dạng chuỗi `"lat,lng"` (vd `"10.775087,106.705696"`) — dán thẳng được vào Google Maps hoặc hầu hết ứng dụng bản đồ |
| `property_url` | URL trang khách sạn |
| `warnings` | Cảnh báo parse (rỗng nếu bình thường) |
| `scraped_at` | Thời điểm crawl (ISO-8601 UTC) |

#### Cấu trúc từng phòng trong `rooms[]`

Có 2 mức chi tiết tuỳ việc actor có gọi được giá hay không (tức có `checkIn` hay không):

| Field | Luôn có | Chỉ có khi cấp `checkIn` (gọi thêm room-grid) |
|-------|:---:|:---:|
| `name`, `room_id`, `bed`, `size`, `view` | ✅ | ✅ |
| `price_per_night` / `currency` / `crossed_out` (có giảm giá) | – | ✅ |
| `sold_out` (còn phòng loại này hay không) | – | ✅ — **phòng hết chỗ vẫn xuất hiện đầy đủ**, chỉ `price_per_night: null` |
| `max_occupancy` (vd `"Tối đa 2 người lớn"`) | – | ✅ |
| `review_score` / `review_text` (điểm review **riêng của loại phòng**, khác điểm chung khách sạn) | – | ✅ |
| `amenity_groups` (tiện nghi theo nhóm, đầy đủ như trên trang phòng) | – | ✅ |
| `images` (toàn bộ ảnh, không chỉ 1 ảnh đại diện) / `image_count` | – | ✅ |

Không có `checkIn` → mỗi phòng chỉ có bộ field cơ bản (`name`, `room_id`, `bed`, `size`, `view`,
`features`, `image_count`, `thumbnail`) lấy từ trang khách sạn thường, không cần gọi thêm request.

***

### Dùng qua API

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<username>/agoda-scraper").call(
    run_input={"searchTerms": ["The Peninsula Bangkok"]}
)
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)
```

#### JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('<username>/agoda-scraper').call({
  searchTerms: ['The Peninsula Bangkok'],
});
console.log(`Dataset: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
```

#### CLI

```bash
echo '{ "searchTerms": ["The Peninsula Bangkok"] }' | apify call <username>/agoda-scraper --silent --output-dataset
```

***

### Cơ chế hoạt động

Actor gọi trực tiếp các endpoint JSON nội bộ của Agoda (không cần trình duyệt):

1. **Tìm kiếm theo tên khách sạn** — `GET /api/cronos/search/GetUnifiedSuggestResult/...?searchText=...`
   → lọc `IsHotel==true` để lấy `hotelId`, tên, thành phố, quốc gia.
2. **Tìm theo vùng/thành phố** (`locations`) — 2 bước:
   - Cùng endpoint suggest ở trên, nhưng lọc entry `CityId == ObjectId != 0` (thành phố thật,
     có khách sạn) để đổi tên vùng → `cityId`.
   - `POST /graphql/search` (operation `citySearch`, query lưu trong
     [src/city\_search\_query.py](src/city_search_query.py)) → liệt kê `hotelId` trong thành phố,
     phân trang tối đa 100/lần (`page.pageSize`/`page.pageNumber`). Header `ag-page-type-id: 644`.
   - Danh sách `hotelId` tìm được feed thẳng vào bước 3 (chi tiết đầy đủ) như mọi nguồn khác.
3. **Chi tiết 1 khách sạn** — 2 nguồn gộp lại:
   - `POST /graphql/property` (operation `propertyDetailsSearch`, query lưu trong
     [src/property\_details\_query.py](src/property_details_query.py)) → tên, địa chỉ, review,
     tiện nghi, mô tả, ảnh, tọa độ. Cần bộ header `ag-*` bắt buộc (thiếu sẽ bị
     `400 Missing required headers`).
   - `GET /api/cronos/property/BelowFoldParams/GetSecondaryData` → rooms, room\_types,
     nearby\_attractions, nearby\_essentials, highlights, location\_highlight, **và
     `category_scores`/`score_distribution`** (nhãn đã dịch sẵn theo ngôn ngữ, lấy từ
     `reviews.demographic` — không cần tự dịch).
4. **Giá theo ngày check-in** (tuỳ chọn, chỉ gọi khi có `checkIn`) —
   `POST /api/v1/property/room-grid` (body template lưu trong
   [src/room\_grid\_template.py](src/room_grid_template.py)) → giá rẻ nhất/đêm, tình trạng còn
   phòng, danh sách offer theo từng loại phòng. Cần header `ag-initiator-api-key` (định danh
   client cố định, không phải auth cá nhân). Hiện chỉ hỗ trợ tiền tệ VND.

Ngôn ngữ kết quả điều khiển bằng header `ag-language-locale` (input `language`) — hỗ trợ tiếng Việt đầy đủ.

> Agoda không công bố API nên schema có thể đổi theo thời gian. Nếu một ngày kết quả rỗng/lỗi,
> mở lại một trang khách sạn Agoda, chụp request `graphql/property` trong DevTools > Network,
> rồi cập nhật `QUERY`/`VARIABLES` trong `property_details_query.py`.
> Nên chạy có proxy và giữ `requestDelay` hợp lý để tôn trọng giới hạn của site.

# Actor input Schema

## `searchTerms` (type: `array`):

Tên khách sạn hoặc điểm đến. Hiệu quả nhất với tên cụ thể (vd: 'The Peninsula Bangkok'). Tên thành phố chung chung chỉ trả về các khách sạn top đầu.

## `propertyUrls` (type: `array`):

URL trang khách sạn Agoda (vd: https://www.agoda.com/the-peninsula-bangkok/hotel/bangkok-th.html). Actor tự tách hotelId. Nếu URL có sẵn checkIn/checkOut (hoặc los)/adults/rooms, actor sẽ tự dùng để lấy GIÁ THỰC TẾ cho khách sạn đó (không cần điền thêm ở dưới).

## `hotelIds` (type: `array`):

ID khách sạn Agoda dạng số nếu đã biết (vd: 10715). Dùng khi bạn đã có sẵn ID.

## `locations` (type: `array`):

Tên vùng/thành phố (vd: 'Hồ Chí Minh') HOẶC dán link trang tìm kiếm Agoda (vd: https://www.agoda.com/vi-vn/search?city=13170\&checkIn=2026-08-01\&checkOut=2026-08-03\&adults=2\&rooms=1&...) - link được ưu tiên vì đã có sẵn cityId, nhanh hơn; nếu link có checkIn/checkOut/adults/rooms thì TẤT CẢ khách sạn tìm được trong vùng sẽ dùng chung tiêu chí đó để lấy giá thực tế. Actor tự tìm tất cả khách sạn trong vùng, giới hạn bởi maxItemsPerLocation.

## `maxItemsPerLocation` (type: `integer`):

Số khách sạn tối đa lấy cho MỖI vùng trong 'Vùng / thành phố cần tìm'. 0 = không giới hạn (có trần an toàn nội bộ ~2000 để tránh kéo cả thành phố). Ví dụ: 200.

## `checkIn` (type: `string`):

Chọn ngày nhận phòng. Dùng để lấy GIÁ THỰC TẾ cho các khách sạn KHÔNG có sẵn checkIn từ URL riêng (vd Hotel IDs, Từ khóa tìm kiếm, hoặc Vùng/thành phố gõ tên thường). Bỏ trống = không lấy giá (nhanh hơn).

## `checkOut` (type: `string`):

Chọn ngày trả phòng. Nếu để trống, actor sẽ tự tính bằng Ngày check-in + Số đêm ở dưới. Chỉ áp dụng cho các khách sạn KHÔNG có sẵn checkIn/checkOut từ URL riêng.

## `lengthOfStay` (type: `integer`):

Số đêm ở lại, dùng để tính ngày check-out khi bạn không chọn 'Ngày check-out' ở trên. Mặc định 1.

## `adults` (type: `integer`):

Dùng cùng với Ngày check-in ở trên cho các khách sạn không có sẵn thông tin này từ URL.

## `rooms` (type: `integer`):

Dùng cùng với Ngày check-in ở trên cho các khách sạn không có sẵn thông tin này từ URL.

## `language` (type: `string`):

Ngôn ngữ dữ liệu trả về (tên phòng, tiện nghi, mô tả, địa điểm lân cận).

## `maxItems` (type: `integer`):

Số bản ghi khách sạn tối đa trên tất cả nguồn. 0 = không giới hạn. Dùng để kiểm soát chi phí.

## `requestDelay` (type: `integer`):

Số giây chờ giữa các lần gọi khách sạn liên tiếp. Tăng lên với batch lớn để giảm nguy cơ bị chặn.

## `proxyConfiguration` (type: `object`):

Cấu hình proxy. Nên dùng Apify Residential proxy cho quy mô lớn.

## Actor input object example

```json
{
  "searchTerms": [
    "The Peninsula Bangkok"
  ],
  "locations": [
    "https://www.agoda.com/vi-vn/search?city=13170"
  ],
  "maxItemsPerLocation": 50,
  "lengthOfStay": 1,
  "adults": 2,
  "rooms": 1,
  "language": "en-us",
  "maxItems": 0,
  "requestDelay": 2,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `hotels` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "searchTerms": [
        "The Peninsula Bangkok"
    ],
    "locations": [
        "https://www.agoda.com/vi-vn/search?city=13170"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("minimal_junglefowl/agoda-hotel-room").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "searchTerms": ["The Peninsula Bangkok"],
    "locations": ["https://www.agoda.com/vi-vn/search?city=13170"],
}

# Run the Actor and wait for it to finish
run = client.actor("minimal_junglefowl/agoda-hotel-room").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "searchTerms": [
    "The Peninsula Bangkok"
  ],
  "locations": [
    "https://www.agoda.com/vi-vn/search?city=13170"
  ]
}' |
apify call minimal_junglefowl/agoda-hotel-room --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=minimal_junglefowl/agoda-hotel-room",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Agoda_hotel_room",
        "description": null,
        "version": "0.0",
        "x-build-id": "mB9w8ZrjBAJy11sdA"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/minimal_junglefowl~agoda-hotel-room/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-minimal_junglefowl-agoda-hotel-room",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/minimal_junglefowl~agoda-hotel-room/runs": {
            "post": {
                "operationId": "runs-sync-minimal_junglefowl-agoda-hotel-room",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/minimal_junglefowl~agoda-hotel-room/run-sync": {
            "post": {
                "operationId": "run-sync-minimal_junglefowl-agoda-hotel-room",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "properties": {
                    "searchTerms": {
                        "title": "Từ khóa tìm kiếm",
                        "type": "array",
                        "description": "Tên khách sạn hoặc điểm đến. Hiệu quả nhất với tên cụ thể (vd: 'The Peninsula Bangkok'). Tên thành phố chung chung chỉ trả về các khách sạn top đầu.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "propertyUrls": {
                        "title": "URL khách sạn",
                        "type": "array",
                        "description": "URL trang khách sạn Agoda (vd: https://www.agoda.com/the-peninsula-bangkok/hotel/bangkok-th.html). Actor tự tách hotelId. Nếu URL có sẵn checkIn/checkOut (hoặc los)/adults/rooms, actor sẽ tự dùng để lấy GIÁ THỰC TẾ cho khách sạn đó (không cần điền thêm ở dưới).",
                        "items": {
                            "type": "string"
                        }
                    },
                    "hotelIds": {
                        "title": "Hotel IDs",
                        "type": "array",
                        "description": "ID khách sạn Agoda dạng số nếu đã biết (vd: 10715). Dùng khi bạn đã có sẵn ID.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "locations": {
                        "title": "Vùng / thành phố cần tìm",
                        "type": "array",
                        "description": "Tên vùng/thành phố (vd: 'Hồ Chí Minh') HOẶC dán link trang tìm kiếm Agoda (vd: https://www.agoda.com/vi-vn/search?city=13170&checkIn=2026-08-01&checkOut=2026-08-03&adults=2&rooms=1&...) - link được ưu tiên vì đã có sẵn cityId, nhanh hơn; nếu link có checkIn/checkOut/adults/rooms thì TẤT CẢ khách sạn tìm được trong vùng sẽ dùng chung tiêu chí đó để lấy giá thực tế. Actor tự tìm tất cả khách sạn trong vùng, giới hạn bởi maxItemsPerLocation.",
                        "items": {
                            "type": "string"
                        }
                    },
                    "maxItemsPerLocation": {
                        "title": "Số khách sạn tối đa mỗi vùng",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Số khách sạn tối đa lấy cho MỖI vùng trong 'Vùng / thành phố cần tìm'. 0 = không giới hạn (có trần an toàn nội bộ ~2000 để tránh kéo cả thành phố). Ví dụ: 200.",
                        "default": 50
                    },
                    "checkIn": {
                        "title": "Ngày check-in",
                        "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$",
                        "type": "string",
                        "description": "Chọn ngày nhận phòng. Dùng để lấy GIÁ THỰC TẾ cho các khách sạn KHÔNG có sẵn checkIn từ URL riêng (vd Hotel IDs, Từ khóa tìm kiếm, hoặc Vùng/thành phố gõ tên thường). Bỏ trống = không lấy giá (nhanh hơn)."
                    },
                    "checkOut": {
                        "title": "Ngày check-out",
                        "pattern": "^(\\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12]\\d|3[01])$",
                        "type": "string",
                        "description": "Chọn ngày trả phòng. Nếu để trống, actor sẽ tự tính bằng Ngày check-in + Số đêm ở dưới. Chỉ áp dụng cho các khách sạn KHÔNG có sẵn checkIn/checkOut từ URL riêng."
                    },
                    "lengthOfStay": {
                        "title": "Số đêm (khi không chọn ngày check-out)",
                        "minimum": 1,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Số đêm ở lại, dùng để tính ngày check-out khi bạn không chọn 'Ngày check-out' ở trên. Mặc định 1.",
                        "default": 1
                    },
                    "adults": {
                        "title": "Số người lớn",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Dùng cùng với Ngày check-in ở trên cho các khách sạn không có sẵn thông tin này từ URL.",
                        "default": 2
                    },
                    "rooms": {
                        "title": "Số phòng",
                        "minimum": 1,
                        "type": "integer",
                        "description": "Dùng cùng với Ngày check-in ở trên cho các khách sạn không có sẵn thông tin này từ URL.",
                        "default": 1
                    },
                    "language": {
                        "title": "Ngôn ngữ kết quả",
                        "enum": [
                            "en-us",
                            "vi-vn",
                            "th-th",
                            "ko-kr",
                            "ja-jp",
                            "zh-cn",
                            "id-id"
                        ],
                        "type": "string",
                        "description": "Ngôn ngữ dữ liệu trả về (tên phòng, tiện nghi, mô tả, địa điểm lân cận).",
                        "default": "en-us"
                    },
                    "maxItems": {
                        "title": "Giới hạn số bản ghi",
                        "minimum": 0,
                        "type": "integer",
                        "description": "Số bản ghi khách sạn tối đa trên tất cả nguồn. 0 = không giới hạn. Dùng để kiểm soát chi phí.",
                        "default": 0
                    },
                    "requestDelay": {
                        "title": "Độ trễ giữa request (giây)",
                        "minimum": 0,
                        "maximum": 30,
                        "type": "integer",
                        "description": "Số giây chờ giữa các lần gọi khách sạn liên tiếp. Tăng lên với batch lớn để giảm nguy cơ bị chặn.",
                        "default": 2
                    },
                    "proxyConfiguration": {
                        "title": "Proxy",
                        "type": "object",
                        "description": "Cấu hình proxy. Nên dùng Apify Residential proxy cho quy mô lớn.",
                        "default": {
                            "useApifyProxy": true,
                            "apifyProxyGroups": [
                                "RESIDENTIAL"
                            ]
                        }
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
