Mục lục
- Agoda Partner Portal (YCS) — cẩm nang điều khiển
- 1. Điều hướng — URL là đường nhanh nhất
- 2. Template replies — mẫu tin
- 3. Message scheduler — ba mốc gửi
- 4. Bẫy tự động hoá qua CDP — đã trả giá
- 5. Sự thật đã xác minh về hiển thị và nội dung
- 6. Ba script
- 7. Còn chưa biết
- 8. Photos 2.0 — ảnh property và ảnh phòng (thêm 16/09/2026)
- 9. Content score (Homes) · Arrival guide · Host profile (thêm 16/09/2026)
- 10. Property ở chế độ YCS KHÁCH SẠN (không phải Homes) — thêm 19/09/2026
Agoda Partner Portal (YCS) — cẩm nang điều khiển
Đúc từ phiên 05/09/2026: tạo 18 mẫu tin + bật Message scheduler cho 6 listing. Đây là tài liệu thao tác (điều hướng, DOM, bẫy tự động hoá). Luật nội dung tin nhắn ở
vault/10-rules/ota-messaging-rules.md§4. Luật set up listing ởagoda-listing-playbook.md. Kho tin nguồn ởvault/16-ota-messages/agoda/.
⚠️ Mặc định Agoda là CHỈ ĐỌC — vault/10-rules/ota-readonly-rule.md.
Ba script ghi bên dưới là ngoại lệ có chủ đích, chỉ chạy khi user ra lệnh trực tiếp cho đúng việc đó.
1. Điều hướng — URL là đường nhanh nhất
| Cần tới | Cách |
|---|---|
| Hộp thư khách của một property | https://portal.agoda.com/mldc/en-us/app/hermes/inbox/ycs/<AGODA_ID> |
| Đổi property | Đổi thẳng <AGODA_ID> trên URL — không cần bấm menu chọn căn ở thanh trên |
| Message scheduler | Trong hộp thư → Automation tools → Scheduled messages |
| Auto reply | Automation tools → Auto reply (khác Scheduled messages, chưa khảo sát) |
| Template replies | Panel cố định bên phải hộp thư, có nút Create new |
Breadcrumb khi vào scheduler: Guest messages > Message preference, hai tab Auto reply | Message scheduler.
Sáu Agoda ID (đối chiếu ../listings.md):
84463574 181 Tô Hiến Thành · 84463562 15 Nước Mặn 5 · 84463560 41 Lê Hy Cát ·
63382515 A La Carte 305 · 84510952 A La Carte 404 · 84463577 A La Carte 502.
25anthuong11 không có listing Agoda.
2. Template replies — mẫu tin
🔴 Mẫu tin thuộc về TỪNG Hotel ID. Không dùng chung giữa các property. Cùng một nội dung vẫn phải tạo lại ở mỗi listing → 6 listing × 3 mốc = 18 mẫu. Tên trùng nhau giữa các căn là cố ý.
Giới hạn: ô Name 100 ký tự · ô Message 2.500 ký tự. DOM không đặt maxlength, nên phải tự đếm.
Quy ước đặt tên (user chốt 05/09/2026)
| Mẫu | Tên | Vì sao |
|---|---|---|
| Xác nhận đặt phòng | 01 Booking confirmed |
nội dung giống hệt mọi căn → không gắn tên căn |
| Nhận phòng | 03 Check-in - <tên căn> |
địa chỉ, mã khoá, Wi-Fi khác nhau → riêng từng căn |
| Trả phòng | 05 Check-out - villa hoặc 05 Check-out - A La Carte |
chỉ hai bản, chia theo giờ trả phòng và cách khoá cửa |
Số 01/03/05 khớp tên file trong vault/16-ota-messages/agoda/, tra ngược được. Tên viết không dấu.
DOM của form mẫu tin
| Thứ | Selector | Ghi chú |
|---|---|---|
| Ô tiêu đề | input[name="Name"] hoặc input[placeholder*="title of your template"] |
🔴 Có property không có attribute name — phải bắt kèm placeholder |
| Ô nội dung | textarea[name="Message"] |
ổn định hơn |
| Nút khi TẠO | Save / Discard |
|
| Nút khi SỬA | Update / Cancel changes |
🔴 tên khác hẳn — dùng nhầm là không tìm thấy nút |
Update bị disabled |
tới khi React ghi nhận thay đổi | phải poll vài nhịp, đừng bấm một lần rồi bỏ |
3. Message scheduler — ba mốc gửi
Ba hàng, mỗi hàng một công tắc + accordion riêng. Bấm Save của chính hàng đó mới lưu.
| Mốc | Ô Select a time |
Lựa chọn |
|---|---|---|
Upon booking confirmation |
không có | gửi ngay khi đặt phòng được xác nhận |
At check-in |
"Select a time before guest check-in" | On the day of check-in · 1 day before · 2 days before · 3 days before |
At check-out |
"Select a time after guest check-out" | On the day of check-out · 1 day after · 2 days after · 3 days after |
🔴 Hai mốc lệch NGƯỢC CHIỀU. Check-in đếm lùi trước ngày đến, check-out đếm tiến sau ngày đi → không có cách nào gửi tin trước ngày trả phòng trên Agoda. Bản Booking gửi tin trả phòng tối hôm trước; bê nguyên mốc đó sang Agoda là chọn nhầm.
Cấu hình đang dùng: booking = ngay khi xác nhận · check-in = 1 day before check-in ·
check-out = On the day of check-out.
Mỗi mốc chỉ gắn được MỘT mẫu tin → phải chọn: At check-out dùng cho tin dặn trả phòng hoặc
tin cảm ơn sau kỳ nghỉ (1 day after check-out), không thể cả hai.
4. Bẫy tự động hoá qua CDP — đã trả giá
Nối Chrome đang đăng nhập qua CDP: xem scripts/ota-read-booking.mjs để lấy mẫu kết nối
(đọc DevToolsActivePort, nối WebSocket, không gọi Page.enable — treo phiên trên portal OTA).
| # | Bẫy | Cách đúng |
|---|---|---|
| 1 | Nút là SPAN/DIV chứ không phải BUTTON → .click() trong Runtime.evaluate vô hiệu |
Dùng Input.dispatchMouseEvent theo toạ độ getBoundingClientRect() |
| 2 | Thiếu mouseMoved trước mousePressed → React không nhận click |
Luôn bắn mouseMoved → mousePressed → mouseReleased |
| 3 | input#toggle là checkbox ẩn, kích thước 0 → bấm không ăn |
Bấm phần tử [role=switch] hiển thị; lấy cả 3 theo thứ tự DOM: 0 booking · 1 check-in · 2 check-out |
| 4 | Gán el.value = x thẳng → React không thấy, Save gửi chuỗi rỗng |
Native setter: Object.getOwnPropertyDescriptor(HTMLInputElement.prototype,'value').set.call(el,v) rồi dispatchEvent(new Event('input',{bubbles:true})) |
| 5 | Đếm nút Edit theo chỉ số toàn trang → bấm nhầm |
Trang có 6 nút tên Edit: 3 của scheduler + 3 của panel Template replies. Tệ hơn: hàng đang bung ra thì mất nút Edit của chính nó, nên số nút tụt 3→2 và mọi chỉ số lệch. Phải giới hạn tìm kiếm trong panel scheduler trước khi đếm |
| 6 | Nút dropdown ở chế độ sửa hiện giá trị đang chọn, không phải chữ Select … |
Regex phải nhận cả hai: /^(Select template\|0[135] )/i |
| 7 | 🔴 --set-method và --set-instructions dùng CHUNG endpoint ArrivalGuide/instructions, mỗi cái ghi null/0 vào trường của cái kia (dính 23/09/2026 ở 15nuocman5) |
Chạy --set-method TRƯỚC, rồi --set-instructions (nó đọc method hiện tại và giữ). Kiểm giữa chừng bằng --dry: body phải có "checkInMethod":5 |
| 8 | 🔴 GET của Agoda bị CACHE. Ghi mô tả xong đọc lại vẫn ra bản cũ → tưởng ghi hỏng, suýt ghi lại lần hai | Đọc xác minh bằng fetch(url+'?_='+Date.now(),{cache:'no-store'}). Đừng kết luận "ghi không ăn" từ một lần GET thường |
| 9 | --set-facilities nhận MẢNG PHẲNG [{facilityId,isSelected,name,from}] |
Bọc {"facilities":[…]} là plan.map is not a function |
| 10 | Điểm ảnh phòng ngủ / phòng tắm không đến từ nhóm Property | Đến từ nhóm ROOM (categoryId 7 + roomTypeId). Khuôn 100/100 của 41lehycat: Property 15 ảnh · Room 16 ảnh với Bedroom 6–7 + Bathroom 4–5 |
| 7 | Dải cảnh báo chống lừa đảo của Agoda phủ lên nút Edit của Template replies → bấm theo toạ độ rơi vào banner, form không mở (gặp ở 502, 21/09/2026; 305 và 404 cùng lúc đó lại không dính) |
Nút này là BUTTON thật nên .click() trong Runtime.evaluate ăn. Ưu tiên DOM .click(), chỉ rơi về chuột CDP khi DOM không mở được form. Kiểm bằng document.elementFromPoint(cx,cy): trả về DIV lạ ⇒ đang bị che |
| 8 | Nút Edit của hàng scheduler là DIV, không phải BUTTON/SPAN/A → mọi selector querySelectorAll('button,span,a') bỏ sót hoàn toàn, báo "không thấy Edit". Ngược với #7, DIV này .click() không ăn |
Quét bằng querySelectorAll('*') lọc innerText.trim()==='Edit', chọn phần tử cùng dòng với nhãn hàng (\|y − y_nhãn\| < 30) rồi bấm bằng chuột CDP. Phân biệt hai bộ bằng toạ độ x: scheduler ở panel trái x≈1481, Template replies ở panel phải x≈1785 |
Chưa thông: ghi vào một hàng scheduler đã cấu hình. Công tắc đã bật thì bấm lại không tắt được,
và đường qua Edit vướng bẫy #5. Hàng chưa cấu hình thì chạy ngon (15/15 mốc ở 5 listing).
→ Muốn sửa hàng đã cấu hình: làm tay, hoặc viết lại phần tìm Edit giới hạn trong panel scheduler.
🟢 ĐỌC hàng đã cấu hình thì thông rồi (21/09/2026). Bấm Edit của hàng (theo bẫy #8) là khung
Message preview bên phải hiện tên mẫu đang gắn + toàn văn thân tin. Đây là cách rẻ nhất để xác minh
một mốc đang gắn đúng mẫu nào — không phải mở form ghi, không chạm Save.
⚠️ scripts/ota-agoda-scheduler.mjs --probe hiện báo "không thấy mục Scheduled messages": Agoda đã
đổi nhãn tab thành Message scheduler, script vẫn tìm chữ cũ. Chưa sửa.
5. Sự thật đã xác minh về hiển thị và nội dung
🟢 Agoda GIỮ dấu xuống dòng trong mẫu tin. Đọc ngược textarea từ portal thấy đúng ký tự \n;
panel Template replies hiện rõ từng khối tách dòng. Format emoji + dòng trắng hiện đúng.
⚠️ Khung Message preview bên phải nuốt ngắt dòng thị giác — chữ chạy liền một mạch.
Đó là CSS của khung preview, không phải tin thật. Đừng kết luận format hỏng từ khung này.
🔴 Agoda che dữ liệu: số thẻ · số điện thoại · email · URL → thay bằng X.
Kakao ID / Zalo dạng chữ có thể lọt lưới — nhưng lọt là dính luật chống off-platform, xem
ota-messaging-rules.md §4. Agoda dán sẵn câu mời khách tố cáo về safety@agoda.com trong mọi cuộc trò chuyện.
🔴 KHÔNG có placeholder. Không chèn được tên khách, không chèn được ngày → mẫu tự động là chữ chết.
Cách né đang dùng: bỏ hết tên và ngày, thay bằng mốc tương đối mà chính scheduler bảo đảm
(tomorrow cho tin check-in gửi trước 1 ngày, today cho tin check-out).
🟢 Agoda tự dịch tin sang ngôn ngữ khách khi gửi → không cần làm bản tiếng Hàn.
⚠️ Nhưng máy dịch chạy qua cả địa chỉ tiếng Việt, tên Wi-Fi và tên thương hiệu — Harth Living có chữ
Living là từ có nghĩa, dễ bị dịch thành nghĩa đen. Chưa test.
🟢 Scheduler đọc thân mẫu SỐNG, không phải bản chụp lúc gán (xác minh 21/09/2026 trên 305).
Sửa nội dung một mẫu trong Template replies là tin tự động của mốc đang gắn mẫu đó đổi theo ngay —
không phải gỡ ra gắn lại. Bằng chứng: sau khi ghi đè 01 Booking confirmed, mở hàng
Upon booking confirmation thì khung Message preview hiện đúng câu vừa thêm.
→ Hệ quả: đổi câu chữ chỉ cần chạy ota-write-agoda-templates.mjs --update, không đụng scheduler.
⏱️ Cửa sổ 14 ngày: không liên hệ được khách sau 14 ngày kể từ ngày trả phòng.
6. Ba script
| Script | Việc | Chạy |
|---|---|---|
scripts/ota-write-agoda-templates.mjs |
tạo / đổi tên / ghi đè thân tin mẫu, đọc nội dung từ khối ```text trong vault/16-ota-messages/agoda/*.md |
--dry · --only <id> · --rename · --update (sửa mẫu đã có cho khớp vault; so trước khi ghi, mẫu nào đã khớp thì bỏ qua; ghi xong mở lại form đọc lại rồi mới báo xong) |
scripts/ota-agoda-scheduler.mjs |
bật 3 mốc + gắn mẫu | --probe (không lưu) · --only <id> · --force |
scripts/ota-agoda-photos.mjs |
ảnh: đọc · tải gốc · upload · đặt ảnh chính · chuyển nhóm Property⇄Room · gán tag (thêm 16/09/2026, xem §8) | --id <id> + --read · --download <dir> (chỉ đọc) · --upload plan.json · --set-main · --reassign … --to room\|property · --tag, mọi lệnh ghi có --dry |
Cả hai cần quyền Bash. Agent không tự cấp được — đưa dòng này cho user dán vào /permissions:
Bash(node scripts/ota-agoda-scheduler.mjs:*)
🔴 Rule không khớp vòng for của shell. for id in …; do node …; done bị chặn dù rule đã có.
Phải gọi từng lệnh node trần một, mỗi listing một lượt.
Nội dung tin không gõ trong script — luôn đọc từ vault, để vault và portal không trôi khỏi nhau.
7. Còn chưa biết
Auto replyhoạt động ra sao (khácScheduled messages) — chưa mở.- ~~Mã
missingPhotoGroupchưa giải nghĩa~~ → đã giải 26/09/2026, xem bảng nhóm ảnh ở §10. - Agoda bắn tin
At check-outvào giờ nào trong ngày → ảnh hưởng câu mở đầuToday, before 11:00 AM. - Máy dịch xử lý địa chỉ tiếng Việt, tên Wi-Fi, tên thương hiệu ra sao.
- Bộ lọc có bắt nhầm mã cửa 8 số (
[đã che]) hay mật khẩu Wi-Fi toàn số thành số điện thoại không. - Hồ sơ YCS đã khai số điện thoại chỗ nghỉ chưa — quyết định câu "call the property number shown on your booking confirmation" có đúng không.
8. Photos 2.0 — ảnh property và ảnh phòng (thêm 16/09/2026)
Trang portal.agoda.com/en-us/app/setting/photos/<AGODA_ID>. Toàn bộ API đọc từ bundle PhotosPage.*.js + api.*.js
(theo read-wizard-copy-from-bundle-not-clicks), không cần bấm nút nào:
| Việc | Gọi gì | Ghi chú |
|---|---|---|
| Đọc toàn bộ ảnh | GET /en-us/api/setting/<id>/Photos/GetAllPhotos |
mảng nhóm: categoryId 5 = Property (roomTypeId 0) · 7 = Room (roomTypeId thật). Mỗi ảnh: photoId · photoToken · pictureTypeId (6 = ảnh chính, 5 = property, 7 = room) · pictureCaptionId (0 = chưa tag) · order |
| Bảng tag | GET …/Photos/GetPhotoCaptions |
97 tag; hay dùng: 13 Exterior view · 19 Lobby · 23 Reception · 9 Entrance · 21 Swimming pool · 25 Restaurant · 5 Buffet · 22 Bar/lounge · 8 Coffee shop · 11 Fitness center · 27 Spa · 121 Massage · 125 Sauna · 154 Bedroom · 3 Bathroom · 139 Separate living room · 102 Kitchen · 1 Balcony/terrace |
| Upload | POST …/Photos/UploadPhoto multipart CategoryId · RoomTypeId · CaptionId · Order · FormFile |
trả {photoId, photoToken, recStatus} — recStatus 1 = lên ngay, khác 1 = chờ duyệt. Gán CaptionId ngay lúc upload thì không dính "Missing tags" |
| Tag · đặt ảnh chính · chuyển nhóm | POST …/Photos/UpdatePhotos {updatePhotoInfoList:[{photoId, photoToken, roomTypeId, imageType, captionId, order}]} |
cùng một endpoint: đổi captionId = tag · imageType 6, order 1 = ảnh chính (ảnh chính cũ phải hạ về 5) · đổi imageType 5↔7 + roomTypeId = chuyển Property⇄Room không cần tải lại (giữ nguyên gốc) |
| Ảnh gốc | lấy uri từ API, thay s=<W>x<H> bằng width×height API trả |
giữ nguyên ce= (ảnh mới ce=3; ép ce=0 → CDN trả 1×1); không có s= chỉ được 2048px. Agoda ép cạnh dài ảnh upload về 2048px — bộ 6016px của 2024 là đường upload cũ |
Bẫy đã gặp:
- Ảnh chính (pictureTypeId 6) không chuyển nhóm / không xoá được khi đang là ảnh chính → đặt ảnh chính mới trước (--set-main), rồi mới --reassign.
- Sau mỗi UpdatePhotos, server đánh số lại order của cả nhóm Room (1→24) theo thứ tự riêng của Agoda — order trên YCS không phải thứ tự mình đặt, đừng dùng nó làm khoá; dùng photoId.
- Header chỉ có chuẩn + Request-Id/traceparent, không có CSRF → fetch() cùng origin trong tab là đủ; upload đi qua DOM.setFileInputFiles vào <input type=file> tạm do script tạo (không đụng input của app).
- 🔴 Upload trả 409 "duplicate" khi file định upload trùng md5 với ảnh đang có trên listing (41LHC 17/09: 70 ảnh cũ chính là file vault) → re-encode (thumbnail 2048 + save lại) trước khi upload, rồi mới xoá bản cũ.
- 🔴 Mã ảnh trên CDN = md5 của file upload, và bản ghi khoá theo md5: tải lại đúng file đã xoá thì Agoda trả cùng photoId cũ và ảnh sống lại trong danh sách (đã trả giá 16/09: agent tải lại restaurant-01 để dò lỗi, làm sống lại tấm user vừa xoá tay). Thấy ảnh biến mất → hỏi user trước, đừng tải lại để thử.
- Sau upload, CDN trả ảnh 1×1 và API trả 0x0 trong ít nhất 30 phút — không phải lỗi, là xử lý bất đồng bộ.
- Trang khách (agoda.com) trễ theo: ngay sau khi đổi ảnh (upload · reassign · tag hàng loạt), card tìm kiếm + gallery trang chi tiết rút xuống chỉ còn 1–2 ảnh (contentImages.hotelImages), trong khi listing khác vẫn 10. Đo 16/09: 2 ảnh lúc 16:45 → đủ 10 ảnh (trần của card) lúc 17:10, tức ~30 phút sau lần UpdatePhotos cuối. Đừng kết luận mất ảnh từ trang khách trong vòng 1 giờ sau khi sửa. Trang chi tiết còn tự chèn 4 ảnh "Nearby attraction" (providerId 999979) không phải của mình.
- 🔴 GET …/Facilities/<id> bị cache trong tab: PUT xong đọc lại ngay bằng fetch() mặc định vẫn thấy giá trị cũ (16/09 tưởng lưu hỏng). Luôn fetch(url,{cache:'no-store'}) hoặc thêm ?_=Date.now() khi đọc lại sau khi ghi.
- photoToken là handle của từng ảnh — không lưu vào vault (luật §9), script --read lấy lại được.
Tiêu chí ảnh lên trang khách (đo 16/09/2026 trên 305 + đối chứng 502, 41 LHC):
- Gallery trang chi tiết (contentImages.hotelImages) = toàn bộ Property photos (305: 11/11) + chỉ 2 Room photos (305: 2/24 · 502: 2/24 — cùng mẫu) + 4 ảnh "Nearby attraction" Agoda tự chèn. 22 ảnh phòng còn lại không vào gallery — chỉ hiện trong card phòng khi ngày tìm còn phòng (chưa xem được vì hai ngày thử đều Sold out).
- Card tìm kiếm = 10 ảnh đầu của gallery (trần 10, mọi listing đều 10).
- Thứ tự: ảnh chính property (pictureTypeId 6) luôn đứng #1; từ #2 trở đi không theo order trên YCS mà theo "AI smart ordering" của Agoda (305: hồ bơi → DELI → spa → nhà hàng → buffet → bar → hồ bơi → gym → massage → hồ bơi bình minh — xen kẽ nhóm Facilities/Dining, đẩy gym/massage xuống cuối). Kéo-thả trên YCS chỉ đổi order, chưa thấy tác dụng lên trang khách.
- 502 có 4 ảnh trên card không tồn tại trong YCS → là ảnh Agoda nhập từ Booking.com (đúng như chân trang YCS nói). 305 không có ảnh nhập kiểu này.
- Muốn một tấm lên card: đặt vào Property photos + gắn tag; muốn nó đứng đầu: đặt làm Main photo; vị trí 2–10 không điều khiển được.
Lần đầu áp dụng: alacarte305 16/09/2026 — hồ sơ ../properties/alacarte305/agoda.md, sổ việc L-101. Lần hai: alacarte502 17/09/2026 — ../properties/alacarte502/agoda.md: 30 ảnh (17 Property + 13 Room) tag ngay lúc upload, 3 bản sao nội thất re-encode 2048px cho md5 khác bản Room, xoá 37 ảnh cũ bằng --delete.
9. Content score (Homes) · Arrival guide · Host profile (thêm 16/09/2026)
Script: scripts/ota-agoda-content.mjs — --score · --read (chỉ đọc) · --set-times · --set-method · --set-bio (ghi, có --dry). ⚠️ Mục này là rubric Homes; property ở chế độ khách sạn (xem §10) chấm 11 mục khác.
Luật chấm điểm chính thức: agoda-homes-content-score-guideline-2025.pdf (Photos 30 · Arrival guide 30 · Amenities 15 · Host 15 · Description 10; điểm refresh ≤24 h).
| Việc | API | Ghi chú |
|---|---|---|
| Điểm từng mục | GET /mldc/en-us/api/reporting/AnalyticsCenter/ContentScoreDetails/<id> |
18 mục, isImproveNeeded + improvements[] (gợi ý chung, không phải tiện ích đã tick) |
| Arrival guide đọc | GET /en-us/api/setting/ArrivalGuide/<id> |
checkInCheckoutTime · checkInDetails · directions · parking · houseRules |
| Giờ nhận/trả | POST …/ArrivalGuide/checkincheckouttime/<id> body = khối checkInCheckoutTime |
giờ dạng "2:00 PM"; null hiện là "Flexible" trên UI nhưng không được tính điểm |
| Cách nhận phòng | POST …/ArrivalGuide/instructions/<id> body = khối checkInDetails |
checkInMethod 1 Reception · 2 Meet and greet · 3 Key self-collection · 4 Lockbox · 5 Door code · 6 Secret key · 7 Email · 8 Other |
| Host profile | GET /mldc/en-us/api/iam/HostProfile/ViewModel · POST …/HostProfile/SaveHostProfile |
cấp tài khoản (chung 6 listing); bio 20–500 ký tự, score đòi ≥100 |
| Mô tả property | POST /en-us/api/setting/PropertyDetails/UpdatePropertyDescription/<id> {description} | client chặn URL (/(https?:\/\/[^\s]+)/); lưu là lên ngay, không qua duyệt (đọc lại GeneralInformation thấy ngay) |
| Facilities | GET/PUT /mldc/en-us/api/setting/Facilities/<id> — PUT {facilities:[{facilityId,isSelected}]} chỉ gửi dòng thay đổi | 88 mục / 8 nhóm; isSelected null = chưa khai · false = đã khai không |
| Giường | POST /en-us/api/setting/RoomSettings/BedConfigurations/<id>/<roomTypeId> {bedroomConfigurations:[{productBedTypeId,numberOfBed,bedroomGroupNumber,optionId:1,productBedTypeLocalName:null}],commonRoomConfigurations:[]} | bedType 1 Single · 3 Double · 4 Queen · 5 King · 8 Sofa; trả true |
| House rules · parking · directions | POST …/ArrivalGuide/houserules|parking|directions/<id> body = đúng khối trong GET | airport transfer: isOffered=true bắt buộc có feeValue (0 = miễn phí); server HTML-encode dấu ' thành ' trong parkingInstruction |
| Occupancy phòng | GET /en-us/api/setting/ChildRate/getroombypropertyId/<id> · POST …/ChildRate/setuproomoccupancy/<id> {setAdultChild:true, rooms:[{roomTypeId, adultSettings:[{baseOccupancy, guestAllowed, maxAdult, maxChildren}], extraBedSettings:[{numberOfExtraBed, numberOfBabyCot}]}]} | 🔴 Toàn null = Agoda bán mặc định 2 người lớn dù Rooms khai max 4 (305 mất mọi khách 3–4 người tới 16/09). Sau POST, rate plan tự sinh occupancyRate {1..n} cùng giá; trang UI childrenrateocc lỗi với property Homes, chỉ API chạy; GET đọc lại vẫn null một lúc — tin response POST + GetRate.occupancyRate |
| Mô tả trên trang khách | contentDetail.contentInformation.description.short (GraphQL agoda.com) | Agoda tự sinh "About us" từ dữ liệu tiện ích, không đăng mô tả partner (đo 16/09 trước và sau khi đổi mô tả). Mô tả partner chỉ còn ý nghĩa cho Content Score / app; sai tiện ích (vd Free parking) sẽ lộ ngay ở đoạn tự sinh |
| Booking settings | GET /en-us/api/supply-pricing-metadata/BookingSettings/GetViewModel/<id> · POST …/UpdateBookingSettings/<id> body = {bookTypeId:{isDirty,value,oldValue}, cancellationPolicyId:{…}, ratePlanSetting:{isDirty,value:[{ratePlanId,maxAdvPurchase,minAdvPurchase,minNightsStay,maxNightsStay}],oldValue:[…]}, dateBasedStayConditions:{…}} | -1 = No limit / không giới hạn; không bọc bookingSettingUpdateModel (400 "RatePlanSetting field is required") |
| Local recommendations | GET/POST …/ArrivalGuide/thingsnearby/<id> {thingsNearby} | |
| Room spec (diện tích · số WC) | POST /en-us/api/setting/RoomSettings/RoomSpecifications/<id>/<rt> body = {maxOccupancy:{isDirty,value,oldValue}, isChildrenAllowed:{…}, maxAllowedFreeChildren:{…}, noOfBathroom:{…}, sizeOfRoom:{…}, externalRoomTypeCode:{…}} (cùng mẫu dirty của BookingSettings; đọc từ bundle RoomSetupBasicDetailsPage + useSaveRoomSpecifications 17/09) | --set-room-spec "<rt>:size=50,bathrooms=1"; trả true; GET đọc lại thấy ngay |
| Địa chỉ ngôn ngữ khác | trong PUT PropertyLocation: localizedStreetAddresses:[{productAddressId:0, languageId, streetName}] | ALL_LANGUAGE: 24 = Tiếng Việt; server trả về kèm productAddressId thật |
-
🔴 Nhãn trên trang khách lấy từ taxonomy KHÁCH SẠN, cùng id với toggle Homes:
Keyless access(272) hiện thành "Check-in [24-hour]";Gym(57) hiện "Fitness center — Free" (không có cờ paid —FacilityProperties: []). Bật toggle Homes là chấp nhận nhãn khách sạn tương ứng. Đối chiếu id ởkipp …/usefulinformation→propertyFacilitiesApi/GetViewModel. -
🔴 Ô bio Host profile là React controlled — native setter + dispatch
inputKHÔNG ăn (ô về 0/500 ngay). PhảiInput.insertTextqua CDP sau khifocus()(gõ như người). BảngSET_VALở §4 chỉ đúng với form Template replies.
| Đổi tên listing | POST …/PropertyDetails/UpdatePropertyName/<id> {propertyName, propertyLocalName} | lưu ngay, propertyLanguageName tự bằng tên mới; luật đặt tên Agoda cấm ngoặc/khuyến mãi — user tự chịu |
| Check-in instructions | POST …/ArrivalGuide/instructions/<id> body = khối checkInDetails (giữ checkInMethod) | ≥25 ký tự; Directions không hiện cho khách, muốn khách đọc điều kiện thì viết vào instructions/tên |
- 🔴 Airport transfer trên Homes chỉ có 3 ô Có/Phí/Phút, không có ô điều kiện → bật là Agoda tự viết "Free airport transfer" + FAQ "Yes" + đoạn AI cho MỌI booking. Điều kiện phải gài ở tên listing + check-in instructions + mẫu tin (305, 16/09).
Luật chấm cần nhớ (đọc lại PDF 17/09): Check-out Time: Specify the check-out from and check-out until time or indicate if it is flexible → chỉ khai checkOutUntil là 0/4 (305 vẫn 0/4 sau khi 91/100). 502 khai cả checkOutFrom = 6:00 AM + checkOutUntil = 12:00 PM (user chốt 17/09) — chờ refresh để xác nhận. Ảnh bedroom/bathroom ở nhóm Room vẫn được tính (305 lên 4/4 + 4/4 chỉ với tag ở Room).
Bẫy 17/09 (502): PUT Facilities trả 200 nhưng GET no-store ngay sau vẫn null cả 88 — PUT lại lần hai → 88/88 khớp. Chưa rõ do xử lý bất đồng bộ hay lần đầu không ăn; luôn đọc lại và so từng dòng với plan trước khi báo xong. Lặp lại ở 404 (23:10): lần 1 chỉ 59/88 ăn (29 dòng nhóm Guest favorites còn null), PUT lại → 88/88. Coi như quy tắc: PUT hai lần, đọc lại giữa hai lần. Cùng ngày: setuproomoccupancy đặt maxAllowedFreeChildren về 0 (305 16/09, 404 17/09) → muốn giữ 1 phải chạy --set-room-spec "<rt>:children_free=1" SAU occupancy. Cùng ngày: 502 đang Non-refundable (13308) chứ không phải 949 như 305 — đừng suy chính sách từ căn này sang căn khác, đọc GetViewModel trước khi hỏi user.
Mục "Add more photos of your property facilities" (2 điểm, 18/09): Agoda dò từng tiện ích đã tick Yes xem có ảnh gắn đúng caption tag hay chưa và liệt kê tên tiện ích thiếu trong improvements[] (41LHC: Bathtub · Dryer; 181: Dryer). Tag Bathroom (3) KHÔNG đếm cho Bathtub — phải là Bathtub (136); ảnh máy giặt tag Washing machine (144) không đếm cho Dryer — cần thêm ảnh tag Clothes dryer (137) dù máy sấy xếp ngay trên máy giặt trong cùng khung. Cách vá rẻ nhất: đổi tag bản Property của ảnh WC có bồn (nhóm Room vẫn giữ đủ Bathroom = số WC) và upload thêm một bản ảnh giặt là re-encode (md5 khác, tránh 409) tag 137. Bảng tag đầy đủ: GET …/Photos/GetPhotoCaptions (Private pool 138 · Sauna 125 · Swimming pool 21 · Garden 38 · Fitness center 11 · Hot tub 17 · Parking lot 166).
Bẫy đã trả giá 16/09:
- 🔴 SaveHostProfile đòi số điện thoại đã xác minh OTP — handler Submit của form kiểm phoneVerified && phoneNumber trước khi gửi; gọi API thẳng khi chưa có SĐT → 500 "Failed to save host profile". Agent không xác minh OTP được → user làm tay (Host profile → Edit → Phone → Verify).
- photoUrlString phải rỗng/null hoặc /avatar/<64hex>_<32hex>.jpg — gửi lại URL pix6.agoda.net cũ là 400 regex; form gốc gửi null khi không đổi ảnh.
- userProfileType chỉ nhận 1 (Individual) / 2 (Company) / null.
10. Property ở chế độ YCS KHÁCH SẠN (không phải Homes) — thêm 19/09/2026
Nhận biết: GET /mldc/en-us/api/layout/<id>/PrivateLayout/Main → MenuViewModel.IsNonHotelAccommodation = false (Homes = true). Dấu hiệu trên UI: star rating có giá trị (5) · menu Rate plans · Room mapping · Cancellation policies · Children Rate and Occupancy · trang Facilities hiện 440 mục / 16 nhóm (Guest favorites 15 · Things to do 47 · Dining 60 · … · Languages 44 · Payment 63) thay vì 88 toggle / 8 nhóm · không có Host profile card. isNhaEnabled trong GeneralInformation và isNhaProperty trong ArrivalGuide vẫn true — không tin hai cờ đó. Lần đầu gặp: 25anthuong11 96450982, sinh ra từ List my property → Fast-track import (URL Booking) 18/09/2026 — wizard không có bước chọn Hotel/Homes; 5 căn tạo trước đó đều là Homes. Không có toggle/API đổi loại hình → xin support (L-120).
Rubric content score bản khách sạn = 11 mục (CMS id đọc từ bundle ContentScorePage.*.js, chữ lấy bằng POST /mldc/en-us/api/reporting/Cms/MultiGet body {languageCode:'en-us',origin:'VN',ids:[…]}):
| CMS | Mục | Trang sửa |
|---|---|---|
| 522393 · 522394 | Add more photos of your property · high-resolution | Photos (API Photos 2.0 như §8 — dùng chung cả hai chế độ) |
| 522395 | Add more photos of your property facilities | Photos — tag khớp facility đã Yes (Parking lot 166 ↔ Car park · Kitchen 102 · Washing machine 144) |
| 522396 · 522397 · 522398 | photos of your rooms · high-res · photos of your room amenities | Photos nhóm Room (Bedroom 154 · Bathroom 3 · Balcony 1 · Kitchen 102) |
| 522399 · 522400 | essential / additional property facilities and services | /en-us/kipp/app/settings/propertysetting/propertyservices/<id> — API vẫn là GET/PUT /mldc/…/Facilities/<id> (440 dòng, PUT {facilities:[{facilityId,isSelected}]}) |
| 522401 | Add room amenities | Rooms (kipp) → POST /en-us/<id>/kipp/api/roomtype/UpdateRoomType |
| 522402 | Update your star rating | chỉ qua chat Agoda (#chat) — import đã gán 5 |
| 522403 | guest age policy | /en-us/app/setting/childrenrateocc/<id> — 4 POST ChildRate/setup* |
Nhóm ảnh missingPhotoGroup — giải 26/09/2026 từ bảng ks trong bundle es.*.js của trang Photos (không bấm thử; kiểm chứng bằng chính API: gắn tag xong, số nhóm tụt ngay trong GetAllPhotos):
| Nhóm | Caption id thuộc nhóm | Nghĩa | Mục content score dò nó |
|---|---|---|---|
| 1 | 8 Coffee shop · 25 Restaurant · 165 Restaurant (private room) | Nhà hàng | 522395 (nếu tick tiện ích nhóm Dining) |
| 2 | 5 Buffet · 104 Food and beverages | Ăn uống | 522395 |
| 3 | 21 Swimming pool · 122 Pool [outdoor] · 138 Private pool | Hồ bơi | 522395 |
| 4 | 27 Spa · 32 Beauty salon · 119 Hot spring bath · 121 Massage · 125 Sauna | Spa | 522395 |
| 5 | 11 Fitness center · 153 Gym/fitness | Gym | 522395 |
| 6 | 36 Kid's club · 37 Playground · 142 Pool [kids] · 151 Kids areas | Trẻ em | 522395 |
| 7 | 24 Recreational facilities · 40 · 41 · 101 · 103 · 105 · 112 · 113 · 114 · 118 · 124 · 126 · 131–135 · 147 · 149 | "Things to do" | 522395 — improvementKeyId 7 = đúng nhóm này |
| 8 | 3 Bathroom | Phòng tắm (Room) | 522398 room amenities |
| 9 | 110 Bed | Giường (Room) | 522398 |
| 10 | 29 View | Tầm nhìn (Room) | 522398 |
⇒ Mục 522395 bản khách sạn đòi ảnh theo nhóm tiện ích đã tick (tick Karaoke/Massage chair thuộc nhóm facility Things to do → cần ≥1 ảnh Property mang caption nhóm 7, vd 24 Recreational facilities). Mục 522398 đòi Room có đủ nhóm 8 · 9 · 10 — tag Bedroom (154) không thay được Bed (110). missingPhotoGroup liệt kê cả nhóm của tiện ích không tick (25AT11 thiếu [1..7] nhưng improvements[] chỉ nêu Things to do) — suy ra chỉ nhóm khớp tiện ích đã tick mới bị chấm; xác nhận khi điểm refresh. Lần đầu áp dụng: 25AT11 26/09 (97 → chờ refresh).
Bộ Homes (522415–522432: 18 mục — ảnh 6 · amenities 2 · mô tả · host 3 · arrival guide 6) không áp cho property hotel; nhưng Arrival guide/mô tả vẫn ghi được bằng API §9 và nên làm sẵn để đổi loại hình không phải làm lại.
API kipp (đọc từ cdn5.agoda.net/ycs/dist/22-*.js + 184-*.js):
- Room: GET /en-us/<id>/kipp/api/roomtype/GetRoomType?roomTypeId=<rt> → Data.Room (Facilities = {Access,Accessibility,Bath,Clothing,Comfort,Dining,Entertainment,Layout,Safety,Others:[id]} · IsChildrenAllowed · NoOfBathroom · SizeOfRoom · ViewId · RoomBedConfigs). Bảng id→tên: …/roomtype/getRoomTypeMasterData (Facilities 10 nhóm · HotelViews · BedTypes). Ghi: POST …/roomtype/UpdateRoomType body = đúng object Room + hotelId, language:'en-us', RoomTypeId (builder c=function(e,t,n,l,…) trong bundle 22). Script: scripts/ota-agoda-room-amenities.mjs --read / --apply plan.json [--dry], tự đọc lại so từng nhóm. Hằng số: nonSmoking 15 · bathtub 37 · smokingAllowed 281. Server bỏ qua MaxAdultsOccupancy/MaxChildrenOccupancy (null), NoOfBedroom tự tính từ bed config.
- Property facilities kipp: GET …/kipp/api/propertyFacilitiesApi/GetViewModel?facilityGroupIds= · POST …/UpsertHotelFacilities — không cần, PUT /mldc/…/Facilities ăn cả 440 (19/09: lần 1 khớp 440/440).
- Age policy (mldc ChildRate, Content-Type: application/json-patch+json, body thường): setupagepolicy {minimumAgeAllowed:0, childRateEnabled:true, childAgeRange:[{ageFrom:0, ageTo:2, recStatus:1, needExtraBed:false}]} → trả childAgeRanges[].hotelChildAgeRangeId · setupuniversalrate {mode:1, ageRanges:[{ageRangeId, stayRate:{value:0, type:4}, breakFast:{}}]} (pricingType 1 Flat · 2 Discount adult · 3 % adult · 4 Free · 5 Not provided) · setupextrabed {isExtraBedEnabled:false, ageRequireExtraBed:null, ageRanges:[], isChannelManager:false} · setuproomoccupancy như §9 · setupfacilities (child facilities, tuỳ chọn). Đọc lại: childviewmodel (ageRange, hotelOccupancy.childRateModeId) + trang wizard hiện Active. Bed config vẫn ghi qua mldc BedConfigurations (chạy được ở hotel-mode).
Bẫy 19/09:
- 🔴 Ảnh dọc 2:3 (2000×3000 hay 1365×2048) bị Agoda ép về cao 1536 → rộng 1023, dưới ngưỡng 1024×768 của mục high-resolution. Resize dọc về đúng 1030×1536 (cắt 9 px) trước khi upload thì Agoda giữ nguyên (181 qua với 1030×1536).
- Ghi hai lần lặp lại: UpdateRoomType lần 1 chỉ ăn IsChildrenAllowed, amenities ăn lần 2; UpdatePropertyDescription lần 1 đọc lại 0 ký tự, lần 2 ăn. Luôn đọc lại no-store so plan.
- ContentScoreDetails trả 204 cho listing mới (cả 404 hôm 17/09) — không phải lỗi, chờ ≤24 h; trang Analytics hiện "No content score data at the moment".
- Tab CDP: chrome-grab mở/đổi tab nên script tự viết phải chọn tab theo URL (TAB=childrenrateocc), không lấy tab portal.agoda.com đầu tiên.
Liên quan: Agoda — cơ chế đã hiểu · Cẩm nang set up listing Agoda · issues.md L-15 · Luật tin nhắn OTA · Luật chỉ đọc OTA