带有 OpenAPI 3.1 描述文件的酒店 REST 接口
面向旅行社与 OTA 的酒店预订 API
按任意坐标搜索酒店,查看每个房型的餐食安排、税费和取消条款,锁定房价、预订并取消,全部通过一个 REST 接口完成。创建免费的沙盒密钥,向下方的 Base URL 发出第一个请求。
文档仅提供英文版本。
- Base URL
https://api.fx-port.com/api/v1- 身份验证
Authorization: Bearer fxp_test_YOUR_KEY- Sandbox
- 免费密钥
- 文档收录的接口
- 14
- 格式
- 采用 HTTPS 传输的 JSON,遵循 OpenAPI 3.1 规范
- 代码示例
- 9 种语言
逐个调用查看一次酒店预订
控制台在 API 客户端窗口中回放文档中的请求:选择一个场景,观看每个请求的构建与发送,并查看返回结果。本页不会调用 API,所有请求和返回结果均来自文档中的示例。
文档中的酒店请求与返回结果,按场景逐个回放
3 个请求:按 ID 搜索一家酒店, 读取房型与房价, 锁定所选房价。
演示会话:请求体取自文档中的示例,日期已顺延以保持在今天之后,耗时仅为示意。本页面不会发送任何请求。
预订入住(上):找到房价并锁定
搜索一家酒店,读取其房型与房价,然后锁定您选择的房价。锁定会返回之后每个调用使用的预订编号。
按 ID 搜索一家酒店
按酒店 ID 搜索会返回酒店卡片及其整个入住期间最低房价的总价,币种为您的代理商币种。
请求 POST /hotels/search_advanced curl https://api.fx-port.com/api/v1/hotels/search_advanced \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "checkin": "2026-12-09", "checkout": "2026-12-12", "residency": "gb", "language": "en", "guests": [ { "adults": 2, "children": [] } ], "hotel_id": "test_hotel_do_not_book" }'响应 200 OK · 400 ms · 2.9 KB 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox ratelimit-limit: 6000 ratelimit-policy: 6000;w=60 x-fx-limit-class: hotel_search { "environment": "sandbox", "search_id": "71498fa9-d3a7-4b6c-81bd-76693be726d1", "status": "complete", "hotels_details": [ { "id": "test_hotel_do_not_book", "hid": 8473727, "name": "Test Hotel (Do Not Book) test", "kind": "Apartment", "address": "Avenida Roble, Frente al Mall Multiplaza, Tegucigalpa", "latitude": 14.079872, "longitude": -87.21677, "postal_code": null, "region": { "id": 3421, "country_code": "HN", "iata": "TGU", "name": "Tegucigalpa", "type": "City", "type_v2": "city" }, "star_rating": 0, "images": [ // ... 2 more ], "serp_filters": [ // ... 6 more ], "amenity_groups": [ // ... 2 more ] } ], "processing_status": { "total_hotels": 1, "cached_hotels": 1, "queued_hotels": 0 }, "queue_info": { "queued_hotel_ids": [], "estimated_completion": null }, "timing": { "total_duration": 0.31, "search_duration": 0.3, "cache_check_duration": 0.01 }, "hotels_pricing": { "test_hotel_do_not_book": { "exchange_rate": 285, "agency_currency": "DZD", "agency_commission": 2.97, "final_price": 1484.97, "b2b_price": 1482 } }, "missing_hotel_ids": [], "missing_hotels_pricing": {} }示例已截取显示. 完整响应的大小(以文档为准): 2.9 KB (1.2 KB gzip)
- PASS 状态码为 200
- PASS $.status 等于 complete
- PASS $.hotels_pricing[*].b2b_price 存在
读取房型与房价
该酒店在入住期间的所有房型与房价,每个都带有餐食安排、税费和取消时间表,以及每个房价的令牌。
请求 POST /hotels/get_rates curl https://api.fx-port.com/api/v1/hotels/get_rates \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "hotel_id": "test_hotel_do_not_book", "checkin": "2026-12-09", "checkout": "2026-12-12", "residency": "gb", "language": "en", "guests": [ { "adults": 2, "children": [] } ] }'响应 200 OK · 425 ms · 1.4 KB 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox ratelimit-limit: 6000 ratelimit-policy: 6000;w=60 x-fx-limit-class: price { "environment": "sandbox", "success": true, "data": { "hotelId": "test_hotel_do_not_book", "hid": 8473727, "rates": [ { "bookHash": "h-14574656-7ce9-5a21-b673-8654c5ebd416", "matchHash": "m-a1f40b22-c086-57c9-b2b5-70c8e59cb27c", "room": { "name": "Standard room", "beddingType": "single bed", "miscRoomType": null, "capacity": null, "bathroom": "private-bathroom", "hasPrivateBathroom": true, "balcony": false, "roomClass": "room", "quality": "standard", "view": null, "floor": null, "bedrooms": null, "isFamily": false, "isClub": false, "genderRestriction": null, "nonSmoking": true }, "meal": { "type": "nomeal", "included": false, "childMealIncluded": false }, "dailyPrices": [ 1, 1, 1 ], "allotment": 77, "isPackage": false, "anyResidency": true, "deposit": null, "noShow": null, "cancellationPolicy": { "freeCancellationBefore": "2026-12-09T21:00:00", // ... 1 more }, "pricing": { "supplierCurrency": "EUR", "agencyCurrency": "DZD", "originalPrice": 3, "agencyCommission": 2.97, // ... 2 more }, "exchangeRate": 285 } ] }, "processingTime": 0.335 }- PASS 状态码为 200
- PASS $.data.rates 包含 1 项
- PASS $.data.rates[0].cancellationPolicy 存在
锁定所选房价
锁价会向供应商重新核对价格,并返回之后每个调用使用的预订编号。它需要读写密钥。
请求 POST /hotels/pre_book curl https://api.fx-port.com/api/v1/hotels/pre_book \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "book_hash": "h-14574656-7ce9-5a21-b673-8654c5ebd416", "price_increase_percent": 0 }'响应 200 OK · 4.50 s · 1.7 KB 200 OK Content-Type: application/json Cache-Control: private, no-store X-Environment: sandbox ratelimit-limit: 1200 ratelimit-policy: 1200;w=60 x-fx-limit-class: booking { "environment": "sandbox", "success": true, "status": "ok", "partnerOrderId": "HMVXX4ZQ3", "priceChanged": false, "data": { "hotelId": "test_hotel_do_not_book", "hid": 8473727, "rates": [ { "bookHash": "p-58bfbfa0-fd1c-4be9-8a2a-54942cae6627", "matchHash": "m-a1f40b22-c086-57c9-b2b5-70c8e59cb27c", // ... 3 more "allotment": 77, "isPackage": false, "anyResidency": true, "deposit": null, "noShow": null, // ... 2 more "exchangeRate": 285 } ] }, "formData": { "partnerOrderId": "HMVXX4ZQ3", "orderId": 757581298, "itemId": 232430616, "paymentTypes": [ { "amount": "3.00", "currencyCode": "EUR", // ... 3 more }, { // ... 5 more } ] } }- PASS 状态码为 200
- PASS $.priceChanged 等于 false
- PASS $.partnerOrderId 存在
预订入住(下):预订、获取凭证并取消
为房间的客人预订已锁定的房价,获取凭证链接,然后在仍可免费取消时取消。预订先返回待确认,几秒钟后才会确认。
预订已锁定的房价
请求中包含预订编号、每个房间的客人和预订人的联系方式。返回结果为待确认,供应商在后台确认。
请求 POST /hotels/book_hotel curl https://api.fx-port.com/api/v1/hotels/book_hotel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "booking_id": "HMVXX4ZQ3", "rooms": [ { "guests": [ { "first_name": "Jane", "last_name": "Smith" }, { "first_name": "John", "last_name": "Smith" } ] } ], "user": { "email": "[email protected]", "phone": "+15555550123" }, "send_email": false }'响应 200 OK · 5.54 s · 524 B 200 OK { "environment": "sandbox", "success": true, "status": "pending", "bookingId": "HMVXX4ZQ3", "partnerOrderId": "HMVXX4ZQ3", "hotelId": "test_hotel_do_not_book", "checkinDate": "2026-12-09", "checkoutDate": "2026-12-12", "pricing": { "totalPrice": 1484.97, "agencyCommission": 2.97, "currency": "DZD", "supplierCurrency": "EUR", "originalPrice": 3 }, "postProcessing": { // ... 3 more }, "processingTime": 5.449, "balanceDebited": false, "transactionCreated": false, "payoutCreated": false }- PASS 状态码为 200
- PASS $.status 等于 pending
- PASS $.balanceDebited 等于 false
获取凭证链接
预订确认后,凭证以 PDF 链接的形式提供:一份含价格供您使用,一份不含价格供旅客使用。
请求 GET /hotels/get_voucher curl 'https://api.fx-port.com/api/v1/hotels/get_voucher?booking_id=HMVXX4ZQ3' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"响应 200 OK · 400 ms · 362 B 200 OK { "environment": "sandbox", "success": true, "data": { "bookingId": "HMVXX4ZQ3", "voucherUrl": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf", "voucherUrlWithPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf", "voucherUrlNoPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith-no-price.pdf", "status": "confirmed" } }- PASS 状态码为 200
- PASS $.data.status 等于 confirmed
- PASS $.data.voucherUrlNoPrice 存在
在免费期内取消
在免费取消截止之前取消,会退还已扣除的全部金额。沙盒预订是真实的测试订单,因此请取消它。
请求 POST /hotels/cancel_hotel curl https://api.fx-port.com/api/v1/hotels/cancel_hotel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "booking_id": "HMVXX4ZQ3" }'响应 200 OK · 3.58 s · 360 B 200 OK { "environment": "sandbox", "success": true, "status": "ok", "bookingId": "HMVXX4ZQ3", "bookingStatus": "refunded", "adminCancel": false, "refund": { "cancellationType": "free", "type": "Free cancellation", "agencyAmount": 1482, "travelerAmount": 1484.97, "currency": "DZD", "providerAmount": 3, "providerCurrency": "EUR" }, "refundProcessed": true, "webhookSent": true, "processingTime": 3.488 }- PASS 状态码为 200
- PASS $.bookingStatus 等于 refunded
- PASS $.refund.cancellationType 等于 free
查找某地周边的酒店
把城市名称转换为坐标,再围绕坐标执行坐标搜索。返回结果列出酒店卡片及其价格,并指出卡片尚未缓存的酒店。
把名称转换为坐标
地点搜索会返回带有纬度和经度的地点。选择其一,并把它的坐标传给坐标搜索。
请求 GET /hotels/locations/search curl 'https://api.fx-port.com/api/v1/hotels/locations/search?query=Tegucigalpa&limit=3' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"响应 200 OK · 120 ms · 897 B 200 OK { "environment": "sandbox", "success": true, "query": "Tegucigalpa", "resultsCount": 2, "locations": [ { "id": "20119", "name": "Tegucigalpa", "displayName": "Tegucigalpa, Honduras", "city": "Tegucigalpa", "countryCode": "HN", "latitude": 14.094204124743296, "longitude": -87.19410705810549, "type": "location", // ... 1 more }, { "id": "TGU", "name": "Toncontin", // ... 7 more } ] }- PASS 状态码为 200
- PASS $.resultsCount 等于 2
- PASS $.locations[0].latitude 存在
搜索坐标周边
坐标搜索需要以米为单位的半径。返回结果把酒店卡片和价格分为两个独立列表,需按酒店 ID 关联,并指出卡片尚未缓存的酒店。
请求 POST /hotels/search_advanced curl https://api.fx-port.com/api/v1/hotels/search_advanced \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "latitude": 14.094204124743296, "longitude": -87.19410705810549, "radius": 15000, "checkin": "2026-12-09", "checkout": "2026-12-12", "residency": "gb", "language": "en", "guests": [ { "adults": 2, "children": [] } ] }'响应 200 OK · 4.47 s · 82.0 KB 200 OK { "environment": "sandbox", "search_id": "4a6877dc-96da-4f32-8c1b-4aaed8b60fe4", "status": "partial", "hotels_details": [ // ... 1 more ], "processing_status": { // ... 3 more }, "queue_info": { // ... 3 more }, "timing": { // ... 3 more }, "hotels_pricing": { // ... 2 more }, "missing_hotel_ids": [ "comfort_inn_tegucigalpa" ], // ... 1 more }示例已截取显示. 完整响应的大小(以文档为准): 82.0 KB (17.0 KB gzip)
- PASS 状态码为 200
- PASS $.status 等于 partial
- PASS $.missing_hotel_ids 包含 1 项
出现问题时
集成过程中会遇到的失败情形,每种都附有 API 发送的返回结果和解决办法。
成功的锁价
下面每种失败情形都基于这个调用改动而来。它返回预订和取消错误会复用的预订编号。
请求 POST /hotels/pre_book curl https://api.fx-port.com/api/v1/hotels/pre_book \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "book_hash": "h-14574656-7ce9-5a21-b673-8654c5ebd416", "price_increase_percent": 0 }'响应 200 OK · 4.50 s · 1.7 KB 200 OK { "environment": "sandbox", "success": true, "status": "ok", "partnerOrderId": "HMVXX4ZQ3", "priceChanged": false, "data": { "hotelId": "test_hotel_do_not_book", "hid": 8473727, "rates": [ { // ... 13 more } ] }, "formData": { "partnerOrderId": "HMVXX4ZQ3", "orderId": 757581298, "itemId": 232430616, "paymentTypes": [ // ... 2 more ] } }- PASS 状态码为 200
- PASS $.priceChanged 等于 false
- PASS $.partnerOrderId 存在
用只读密钥执行写入调用
锁定房价、预订和取消都需要读写密钥。只读密钥会被拒绝,并返回指明所缺权限的权限错误。
请求 POST /hotels/pre_book curl https://api.fx-port.com/api/v1/hotels/pre_book \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "book_hash": "h-14574656-7ce9-5a21-b673-8654c5ebd416", "price_increase_percent": 0 }'响应 403 Forbidden · 90 ms · 582 B 403 Forbidden { "environment": "sandbox", "success": false, "errors": [ { "code": "read_write_permission_required", "type": "permission_error", "title": "Read+Write permission required", "message": "This endpoint requires an API key with read_write permission.", "field": null, "details": {}, "documentation_url": "https://fx-port.com/docs/errors#read_write_permission_required" } ], "meta": { "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "status": 403 }, "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "detail": { "error": "read_write_permission_required", "message": "This endpoint requires an API key with read_write permission." } }- FAIL 状态码为 200 (实际为 403)
- PASS 错误码为 read_write_permission_required
- PASS $.meta.status 等于 403
已不存在的房价
已过期的房价令牌,或涨幅超出您上限的价格,会作为找不到的房价被拒绝。请重新读取房价并重新选择。
请求 POST /hotels/pre_book curl https://api.fx-port.com/api/v1/hotels/pre_book \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "book_hash": "h-14574656-7ce9-5a21-b673-8654c5ebd416", "price_increase_percent": 0 }'响应 400 Bad Request · 140 ms · 359 B 400 Bad Request { "environment": "sandbox", "success": false, "errors": [ { "code": "rate_not_found", "type": "supplier_error", "title": "Rate not found", "message": "Rate not found", "field": null, "details": {}, "documentation_url": "https://fx-port.com/docs/errors#rate_not_found" } ], "meta": { "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "status": 400 }, "request_id": "req_7f0c2e9a41b84d6e8a35c1d2" }- FAIL 状态码为 200 (实际为 400)
- PASS 错误码为 rate_not_found
- PASS $.meta.status 等于 400
这些日期没有房价
酒店无房并不是错误:返回结果是成功的,房价列表为空。请检查列表的长度。
请求 POST /hotels/get_rates curl https://api.fx-port.com/api/v1/hotels/get_rates \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "hotel_id": "test_hotel", "checkin": "2026-12-09", "checkout": "2026-12-12", "residency": "gb", "language": "en", "guests": [ { "adults": 2, "children": [] } ] }'响应 200 OK · 250 ms · 108 B 200 OK { "environment": "sandbox", "success": true, "data": { "hotelId": null, "hid": null, "rates": [] }, "processingTime": 0.16 }- PASS 状态码为 200
- PASS $.data.rates 包含 0 项
- PASS $.data.hotelId 等于 null
入住时间过长
日期会在调用供应商之前检查:晚数超出允许范围的入住会被立即拒绝,并返回指明字段的代码。
请求 POST /hotels/search_advanced curl https://api.fx-port.com/api/v1/hotels/search_advanced \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "hotel_id": "test_hotel_do_not_book", "checkin": "2026-12-09", "checkout": "2027-01-13", "residency": "gb", "language": "en", "guests": [ { "adults": 2, "children": [] } ] }'响应 400 Bad Request · 80 ms · 580 B 400 Bad Request { "environment": "sandbox", "success": false, "errors": [ { "code": "stay_too_long", "type": "validation_error", "title": "Stay too long", "message": "A stay can be at most 30 nights ('checkout' is 35 nights after 'checkin').", "field": "checkout", // ... 2 more } ], "meta": { "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "status": 400 }, "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "detail": { "error": "stay_too_long", "message": "A stay can be at most 30 nights ('checkout' is 35 nights after 'checkin').", "field": "checkout" } }- FAIL 状态码为 200 (实际为 400)
- PASS 错误码为 stay_too_long
- PASS $.meta.status 等于 400
过早取消
只有已确认的预订才能取消。刚预订后它仍是待确认状态,调用会因状态无效错误而被拒绝。
请求 POST /hotels/cancel_hotel curl https://api.fx-port.com/api/v1/hotels/cancel_hotel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "booking_id": "HMVXX4ZQ3" }'响应 400 Bad Request · 110 ms · 512 B 400 Bad Request { "environment": "sandbox", "success": false, "errors": [ { "code": "invalid_status", "type": "validation_error", "title": "Invalid status", "message": "Booking is 'pending', can only cancel 'confirmed' bookings", "field": null, "details": {}, "documentation_url": "https://fx-port.com/docs/errors#invalid_status" } ], "meta": { "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "status": 400 }, "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "detail": { "error": "invalid_status", "message": "Booking is 'pending', can only cancel 'confirmed' bookings" } }- FAIL 状态码为 200 (实际为 400)
- PASS 错误码为 invalid_status
- PASS $.meta.status 等于 400
供应商已满负荷
繁忙的供应商会在发送任何内容之前拒绝调用。请等待重试请求头中给出的秒数,然后重复同一个调用。
请求 POST /hotels/book_hotel curl https://api.fx-port.com/api/v1/hotels/book_hotel \ -H "Authorization: Bearer fxp_test_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "booking_id": "HMVXX4ZQ3", "rooms": [ { "guests": [ { "first_name": "Jane", "last_name": "Smith" }, { "first_name": "John", "last_name": "Smith" } ] } ], "user": { "email": "[email protected]", "phone": "+15555550123" }, "send_email": false }'响应 503 Service Unavailable · 90 ms · 623 B 503 Service Unavailable Retry-After: 3 { "environment": "sandbox", "success": false, "errors": [ { "code": "supplier_busy", "type": "supplier_error", "title": "Supplier busy", "message": "The supplier is temporarily at capacity; retry after the time given in the Retry-After header.", "field": null, // ... 1 more "documentation_url": "https://fx-port.com/docs/errors#supplier_busy" } ], "meta": { "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "status": 503 }, "request_id": "req_7f0c2e9a41b84d6e8a35c1d2", "detail": { "error": "supplier_busy", "message": "The supplier is temporarily at capacity; retry after the time given in the Retry-After header." } }- FAIL 状态码为 200 (实际为 503)
- PASS 错误码为 supplier_busy
- PASS 响应头 Retry-After 存在
跟踪并核对预订
列出您最近的酒店预订,打开其中一笔查看状态和金额,并获取它的凭证。已取消的预订仍保留其凭证链接。
列出您的酒店预订
历史记录按时间倒序列出您的代理商的预订。可按产品、状态和日期筛选。
请求 GET /history curl 'https://api.fx-port.com/api/v1/history?product=hotels&limit=1' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"响应 200 OK · 160 ms · 1.5 KB 200 OK { "environment": "sandbox", "success": true, "data": [ { // ... 3 more "booking_id": "HMVXX4ZQ3", // ... 29 more } ], "pagination": { "page": 1, "limit": 1, "total": 86, "total_pages": 86, "hasMore": true, "has_more": true }, "meta": { "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d", "agency_id": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d", // ... 2 more } }- PASS 状态码为 200
- PASS $.data[0].product 等于 hotels
- PASS $.pagination.limit 等于 1
打开一笔预订
预订详情显示状态、旅客支付的金额、代理商被扣除的金额、取消后的退款以及凭证链接。
请求 GET /bookings/{booking_id} curl 'https://api.fx-port.com/api/v1/bookings/HMVXX4ZQ3?product=hotels' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"响应 200 OK · 180 ms · 2.4 KB 200 OK { "environment": "sandbox", "success": true, "data": { "product": "hotels", "id": "34a08cf3-dff6-45c6-bdae-882061aa78f5", "bookingId": "HMVXX4ZQ3", "booking_id": "HMVXX4ZQ3", "status": "refunded", "environment": "sandbox", "agencyId": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d", "agency_id": "0b1c2d3e-4f50-4a6b-8c7d-9e0f1a2b3c4d", // ... 3 more "totalPrice": 1484.97, "total_price": 1484.97, "netPrice": 1482, "b2b_price": 1482, "agencyCommission": 2.97, // ... 21 more }, "meta": { // ... 3 more } }- PASS 状态码为 200
- PASS $.data.status 等于 refunded
- PASS $.data.netPrice 等于 1482
再次获取凭证链接
凭证调用返回与预订详情相同的链接,请求更轻量。
请求 GET /hotels/get_voucher curl 'https://api.fx-port.com/api/v1/hotels/get_voucher?booking_id=HMVXX4ZQ3' \ -H "Authorization: Bearer fxp_test_YOUR_KEY"响应 200 OK · 400 ms · 362 B 200 OK { "environment": "sandbox", "success": true, "data": { "bookingId": "HMVXX4ZQ3", "voucherUrl": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf", "voucherUrlWithPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith.pdf", "voucherUrlNoPrice": "https://files.example.com/hotel-bookings/HMVXX4ZQ3-Jane-Smith-no-price.pdf", "status": "confirmed" } }- PASS 状态码为 200
- PASS $.data.bookingId 等于 HMVXX4ZQ3
- PASS $.data.voucherUrlNoPrice 存在
酒店预订流程,逐步说明
一次酒店预订是一串简短的调用,每个调用都会把一个标识符交给下一个调用。请按此顺序构建,并通过链接查看每个调用的指南和接口参考。
查找地点
地点搜索会把用户输入的城市、区域或机场转换为带坐标的地点。保留用户所选地点的
latitude和longitude。如果您知道酒店名称,名称搜索会返回它的id。执行坐标搜索
发送坐标和以米为单位的
radius、日期、每个房间的客人以及居住国。返回结果包含每家酒店的精简卡片,以及其整个入住期间最低房价的总价。请按酒店 ID 把卡片与价格关联起来。打开酒店并查看房型
获取酒店的完整内容用于酒店页面,并获取该次入住的房型与房价。每个房价都包含餐食安排、税费、取消时间表和
bookHash,这是一个有效期为 30 分钟的令牌。预先预订房价(pre_book)
把
bookHash发送到pre_book,并在price_increase_percent中填写您可接受的涨幅。供应商会重新核对价格,FX-Port 返回partnerOrderId,即之后每个调用使用的预订编号。此调用、book_hotel和cancel_hotel都需要读写密钥。预订入住
把预订编号、每个房间的客人以及预订人的联系方式发送到
book_hotel。预订确认时才会从您的代理商账户扣款,返回结果为pending。等待确认
每隔 2 秒读取一次预订,直到其状态变为
confirmed。这需要 4 至 14 秒。FX-Port 不发送 Webhook,因此需要通过轮询获知结果。交付凭证,或取消预订
为旅客获取凭证链接,或对已确认的预订调用
cancel_hotel。取消的返回结果会说明退回代理商的金额和退回旅客的金额。
在调用之间需要携带的内容
| 来源 | 需要保留 | 发送到 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
酒店接口一览
酒店 API 共有 14 个接口:地点查询、酒店内容、房价、预订与取消,以及您的预订读取。每一行都链接到对应的接口参考页,其中有全部字段、示例和错误代码。
| 接口 | 用途 | 密钥 |
|---|---|---|
GET /api/v1/hotels/locations/search | 为输入的城市、区域或机场返回带坐标的地点。 | 只读 |
GET /api/v1/hotels/name-search | 按酒店名称模糊搜索,容许拼写错误和重音符号,返回酒店 ID 和匹配得分。 | 只读 |
POST /api/v1/hotels/search-by-name | 同样的名称搜索,参数放在 JSON 请求体中。 | 只读 |
POST /api/v1/hotels/search_advanced | 坐标搜索:搜索某个坐标周边的酒店,或按 ID 查找一家酒店,返回精简卡片及整个入住期间最低房价的总价。 | 只读 |
POST /api/v1/hotels/search | 按 ID 批量获取多家酒店的内容,可返回精简卡片或完整文档。 | 只读 |
POST /api/v1/hotels/details | 按 ID 获取已存储的酒店文档,用于您自己的酒店目录。 | 只读 |
POST /api/v1/hotels/get_hotel_info | 获取一家酒店用于其页面的完整内容:简介、照片、房型和政策。 | 只读 |
POST /api/v1/hotels/get_rates | 一家酒店在某次入住期间的所有房型与房价,含餐食安排、税费、取消条款和价格。 | 只读 |
POST /api/v1/hotels/pre_book | 锁定价格:供应商重新核对房价,返回结果带有预订编号。 | 读写 |
POST /api/v1/hotels/book_hotel | 为每个房间的客人预订已锁定的房价。返回待确认,供应商几秒钟后确认。 | 读写 |
POST /api/v1/hotels/cancel_hotel | 取消已确认的预订,返回结果中包含退还给代理商和旅客的金额。 | 读写 |
GET /api/v1/hotels/get_voucher | 凭证 PDF 的链接:一份含价格,一份不含价格。 | 只读 |
GET /api/v1/history | 您的代理商的预订,按时间倒序,仅筛选酒店。 | 只读 |
GET /api/v1/bookings/{booking_id} | 一笔预订的完整信息:状态、价格、退款和凭证链接。 | 只读 |
酒店 API 涵盖的内容
按坐标周边或按名称查找酒店
以半径搜索某个坐标周边,或按名称或 ID 查找酒店。地点搜索会把输入的目的地转换为坐标搜索所需的坐标,因此您的搜索框可以接受城市、区域或机场。
精简卡片与完整文档
结果列表需要小卡片,酒店页面需要完整文档,因此 API 用同一个酒店 ID 提供两者。一张卡片约 5 KB,完整文档平均 35 至 45 KB,建议都按酒店 ID 缓存。卡片带有筛选标签和设施分组,可在您自己的界面中筛选。酒店内容为英文,而房价中的房型名称遵循您发送的语言。
含餐食、税费和取消条款的房型
每个房价均为预付,并注明餐食安排、税费以及免费取消截止的确切时间。旅客在酒店支付的税费(例如城市税)会单独列出,从不向您的代理商收取。部分房价只适用于部分居住国,因此请发送客人的居住国。
预订前先锁定价格
锁价会向供应商重新核对价格。您可以设定从查看房价到锁价之间价格最多可上涨多少。超出该限度调用会失败,您需要重新读取房价;在限度之内,返回结果会标明价格变动并附上新价格。
使用您自己的佣金预订
填写每个房间的客人,附上预订人的联系方式,并选择是否由 FX-Port 发送确认邮件。佣金按代理商的规则计算,也可以为单次预订设置为每间房的固定金额或百分比。
给您和旅客的凭证
每个已确认的预订都有一份含价格的凭证 PDF 供您留存,以及一份不含价格的凭证 PDF 供旅客使用。这些链接是永久的公开地址,任何人都可以打开,因此只把不含价格的链接交给旅客。取消之后这些链接仍然有效,所以不要再次发放凭证。
预订历史与详情
随时读取您的预订:按时间倒序的历史列表,以及包含状态、价格、取消后的退款和凭证链接的详情。超时之后,您可以通过它了解实际发生了什么。
价格、佣金与取消,一目了然
每个酒店价格都涵盖整个入住期间和全部房间,币种为您的代理商币种。您无需发送币种:它由您的密钥确定,携带币种的请求会被拒绝。
价格的三个金额
| 金额 | 含义 |
|---|---|
旅客价格totalPrice | 旅客为整个入住期间和所有房间支付的金额,也是应当展示的价格。 |
代理商佣金agencyCommission | 您的佣金,即旅客价格中留给您的代理商的部分。 |
您的实付金额netPrice | 从代理商余额中扣除的金额:旅客价格减去您的佣金。搜索和预订详情会返回该金额;其他返回结果需要您自行减去佣金。 |
搜索对同样的金额使用 snake_case 命名:final_price、agency_commission 和 b2b_price。
在文档中的沙盒示例里,旅客价格为 1,484.97 DZD,佣金为 2.97 DZD,您的代理商被扣款 1,482.00 DZD。沙盒本身不会扣款。
不要根据 originalPrice 计算价格:它是供应商以其自身币种给出的价格,仅供参考。
设置您自己的佣金
默认由代理商的规则决定佣金。如需为单次预订更改,请发送 commission_override,值为每间房的固定金额或百分比。代理商被扣除的金额保持不变,变化的是旅客价格。
在酒店支付的税费
每个房价都会按名称列出其税费。标注为不含在内的税费由旅客在酒店支付,在旅客价格之外另付,从不向您的代理商收取。其金额保持酒店所标注的币种,不做换算。
预订前先了解取消条款
为生产环境而构建
预订会动用您的代理商余额,因此失败时的规则都已写明:统一的错误格式、一张列明哪些调用可以安全重复的表,以及每个响应中都能读取的限制。
统一的错误格式
了解哪些调用可以安全重复
即使返回结果没有送达您,第一次预订调用也可能已经成功,因此盲目重试是需要避免的错误。下表列出各个调用的允许情况。
| 调用 | 可以重复吗? | 处理方式 |
|---|---|---|
| 搜索、内容、房价、凭证和预订读取 | 可以 | 可以随意重复;当 API 返回 429 或 5xx 时请退避等待。 |
| 锁定房价 | 可以 | 一分钟内用相同的价格上限锁定同一个房价会得到相同的返回结果,因此重试不会产生第二个订单。 |
| 预订酒店 | 不可以 | 第二次调用会返回 409 duplicate_booking,并且不会到达供应商。超时或出现 5xx 之后,请先读取该预订:如果它存在,说明预订已经成功。唯一的例外是 503 supplier_busy,它在发送任何内容之前就被拒绝了。 |
| 取消预订 | 超时后可以 | 再调用一次即可完成取消,即使供应商此前已经取消。条件允许时请先读取该预订。 |
没有 Webhook,也没有幂等键
FX-Port 不发送 Webhook,API 也没有
Idempotency-Key请求头。请每隔 2 秒轮询预订,直到它不再是pending;在重复执行预订或取消的调用之前,请先读取该预订。预订和取消响应中的 Webhook 标记是 FX-Port 的内部步骤,不是发给您的消息。密钥、权限与 IP 列表
沙盒密钥以
fxp_test_开头,正式密钥以fxp_live_开头,并作为 Bearer 令牌放在Authorization请求头中发送。锁定房价、预订和取消需要读写密钥,在正式环境使用的读写密钥应限定在 IP 允许列表内。请只从您的服务器通过 HTTPS 调用 API。FX-Port 只保存每个密钥的哈希值,因此丢失的密钥无法找回;密钥和 IP 列表的更改最多需要 5 分钟才会生效。可读取的速率限制
限制按密钥和每分钟计算,并分为搜索与验价、预订和其他三个独立的组。每个响应都带有
ratelimit-limit、ratelimit-remaining和ratelimit-reset,429还会附加Retry-After。带有supplier_busy的503在发送任何内容之前就被拒绝了,因此等待之后可以重复同一个调用。稳定的名称与版本
请求字段使用
snake_case。早期的写法仍然有效,返回结果会指出应使用的写法;响应也会在旧键旁增加对应的snake_case键,因此现有的集成可继续使用。版本是 URL 的一部分,可能破坏集成的更改会以新版本发布,并先在更新日志中公布。
限制与耗时
这些限制会在调用任何供应商之前检查,因此超出限制的请求会很快失败,并返回指明字段的代码。耗时是各指南给出的范围,最后一张表中的搜索于 2026年11月1日 在沙盒中测得:仅供参考,并非承诺。
请求限制
调用耗时
| 调用 | 典型耗时 |
|---|---|
| 搜索单家酒店 | 0.4-0.7秒 |
| 坐标周边搜索 | 4-20秒 |
| 房型与房价 | 0.5-5秒 |
| 锁定房价 | 4-5秒 |
| 预订,直至返回待确认 | 3-6秒 |
| 从待确认到已确认 | 4-14秒 |
| 确认后的凭证链接 | 0-10秒 |
| 取消预订 | 1-4秒 |
坐标搜索的大小与速度
| 搜索 | 酒店 | 返回数据大小 | 耗时 |
|---|---|---|---|
| 按 ID 查找单家酒店 | 1 | 2.9 KB | 0.4-0.7秒 |
| 努克周边,半径 4 公里 | 5 | 20 KB | 1.5秒 |
| 特古西加尔巴周边,半径 15 公里 | 15 | 82 KB | 4.1秒 |
| 洛杉矶周边,半径 5 公里 | 73 | 362 KB | 9.6秒 |
| 巴黎市中心周边,半径 5 公里 | 1,818 | 8.5 MB | 19.3秒 |
Accept-Encoding: gzip,并且不要为每一页重复同一次搜索。从沙盒到正式环境
沙盒密钥与正式密钥访问相同的接口,因此上线只需更换密钥,无需修改代码。所有 FX-Port API 的入门步骤相同;下面的规则是酒店专有的。
创建账户
注册 FX-Port 账户。沙盒密钥免费,沙盒预订不会产生任何实际费用。
创建沙盒密钥
在仪表盘的 API 页面创建以
fxp_test_开头的密钥。只读密钥可以搜索和读取数据;读写密钥还可以创建测试预订。发送第一个请求
只有一个 Base URL,密钥以 Bearer 令牌的形式放在
Authorization请求头中。快速入门会带您完成第一次调用。准备就绪后切换到正式环境
换上
fxp_live_密钥即可。正式环境在您的代理商获批后可用;在此之前,API 会返回403 agency_not_active。真实预订从已充值的余额中支付。
沙盒允许您做什么
可以搜索任意酒店并查看真实价格。只能预订供应商的测试酒店:
test_hotel_do_not_book适用于所有居住国,test_hotel适用于居住国dz、ru和us。对其他任何酒店锁定房价都会返回409hotel_not_bookable_in_sandbox,并列出测试酒店。取消每一笔沙盒预订
沙盒预订是供应商测试合同下的真实订单,并附有真实的凭证。请逐一取消:免费取消持续到入住当天。沙盒不会扣款,预订返回结果会通过将
balanceDebited设为false来说明这一点。正式环境有哪些变化
正式预订在确认时从您的代理商余额扣款,并且在预订之前会先检查余额。余额不足时,预订调用会返回
402insufficient_balance。沙盒标志balanceDebited、transactionCreated和payoutCreated在正式环境中不存在。加快上手的工具
借助 OpenAPI 3.1 文件可以生成客户端和测试,借助 Postman 集合可以手动发送每个酒店请求。每个文档页面也提供 Markdown 版本,
llms.txt索引则为 AI 助手列出这些页面。代码示例涵盖 9 种语言。
酒店 API 适合谁
旅行社
您向客户销售住宿,需要清楚每笔预订让您付出多少成本。
- 旅客价格、您的佣金和代理商被扣除的金额分别列出。
- 当客户协议需要时,可为单次预订设置佣金。
- 在确定预订之前,先阅读每个房价的取消条款。
在线旅游代理商与预订平台
搜索页、酒店页和结账流程由您自己构建。
- 用精简卡片填充结果列表,只为访客打开的酒店读取完整文档。
- 根据文档中的限制与耗时来确定半径、缓存和轮询间隔。
- 用 OpenAPI 文件生成客户端,并用 Postman 集合试用每个调用。
评估供应商的团队
您需要知道哪些免费、哪些需要审批、哪些有文字记载。
- 沙盒密钥免费,可搜索任意酒店;正式密钥需要已获批的代理商。
- 限制、错误代码、重试规则和版本管理都公布在文档中。
- 集成问题请通过电子邮件发给开发团队,并附上失败调用的请求 ID。
酒店 API 常见问题解答
使用酒店 API 需要审批吗?
无需审批即可开始:创建账户,生成沙盒密钥,即可免费基于它开发。正式密钥只有在您的代理商获批后才可使用,在此之前调用会被拒绝,并提示代理商尚未激活,而沙盒密钥仍可继续使用。正式环境的预订还需要代理商余额已充值。
在沙盒中可以预订任意酒店吗?
在沙盒中可以搜索任意酒店并查看真实价格,但只能预订供应商的测试酒店。其中一家适用于所有居住国,另一家只适用于部分居住国。每笔沙盒预订都是真实的测试订单,因此请取消您创建的每一笔。免费取消持续到入住当天,且不会扣款。
酒店预订需要多久才能确认?
预订调用返回的状态是待确认。随后供应商在后台确认,通常在 4 至 14 秒之后。请每隔 2 秒读取一次预订,直到它已确认,再获取凭证。FX-Port 不发送 Webhook,因此需要通过轮询获知结果。
取消和退款如何运作?
每个房价都会注明免费取消何时截止。在该时间之前取消已确认的预订,已扣除的全部金额都会退还给您的代理商。之后的退款按该房价的违约金计算,不可退款的房价则不退任何金额。API 没有修改预订的调用,因此更改就是先取消、再重新预订。
价格使用哪种币种?我的佣金如何处理?
价格以您的代理商币种给出,由您的密钥确定,因此您无需发送币种。每个价格都会显示旅客价格、您的佣金以及代理商被扣除的金额。佣金遵循代理商的规则,也可以为单次预订设置为每间房的固定金额或百分比。
返回数据有多大?如何保持结果列表的速度?
列表使用精简卡片,只为访客打开的酒店使用完整文档,因为完整文档要大好几倍。坐标搜索不分页,最多返回 5,000 家带价格的酒店,所以请把半径控制在屏幕所显示的范围内,并请求压缩后的返回数据。按酒店 ID 缓存酒店内容。
有 Webhook 或幂等键吗?
都没有。请通过轮询状态来跟踪预订,并且在重复任何预订或取消的调用之前,先读取该预订。对同一个预订编号再次调用预订会因重复而被拒绝,并且不会到达供应商,但这只是一道安全保障,不是幂等键。
入住、房间和客人有哪些限制?
一次入住最长 30 晚,入住日期最多可提前 400 天,一次搜索最多包含 9 间房。每间房有各自的成人和儿童,并需填写每个儿童的年龄。API 会在调用供应商之前检查这些限制,因此超出限制的请求会很快失败,并指出出错的字段。
如何获得帮助?API 如何管理版本?
请通过电子邮件联系开发团队,并附上失败调用的请求 ID。版本是 URL 的一部分。仅新增内容的更改(例如新增字段)不会改变版本,而可能破坏集成的更改会以新版本发布,并先在更新日志中公布。
可以让 AI 助手使用这些文档吗?
可以。文档的每个页面都提供 Markdown 版本,索引文件为 AI 助手列出这些页面,OpenAPI 文件则描述每个操作,并附有示例和错误代码。请把 API 密钥保存在您的服务器上,不要放进任何提示词。
相关 API 与文档
旅程很少止于酒店。机票和 eSIM API 与酒店 API 共用 Base URL、密钥格式和错误格式,因此一个客户端和一套错误处理即可服务全部。