Geo search: hotels around a point
Geo search: finds and prices the hotels around a point for a stay.
/api/v1/hotels/search_advancedSend latitude, longitude and radius (meters, required) with the dates, the guests and the residency; the coordinates of a place come from the location search. The same call searches one hotel when you send hotel_id instead. The answer has two parts that you join by hotel id: hotels_details[] holds the MINI card of each hotel (identity, place, photos, amenities, no rates) and hotels_pricing holds the price of the cheapest rate of each hotel for the whole stay. Call get_rates for the rooms, meals and cancellation terms of the hotel the user picks. Hotels that are priced but whose content FX-Port has not cached yet are in missing_hotel_ids: read each one with get_hotel_info. The answer is always one JSON body: stream=true and Accept: text/ are ignored for API keys. There is no pagination: a 5 km radius around a big city can return 1,800 hotels and 8 MB, so keep the radius to what the screen needs. A search answers at most 5,000 hotels: when there are more the answer says truncated and how many were found. A geo search takes 4 to 20 seconds, a search of one hotel less than a second. Identical searches of your agency that arrive at the same moment are merged into one supplier call; each caller still gets its own request_id and headers. Do not send currency. A value written in another well-defined way is read and reported in warnings (coerced_value): a number as text, a date with a midnight time, a sub-territory residency, a radius outside 100 to 70,000 meters, which is moved to the nearest bound. What cannot be read keeps its error code. In the sandbox the search runs on real hotels and prices, but only the supplier test hotels can be booked.
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": 48.8566,
"longitude": 2.3522,
"radius": 1000,
"checkin": "2026-12-01",
"checkout": "2026-12-04",
"residency": "gb",
"guests": [
{
"adults": 2,
"children": []
}
]
}'{
"environment": "sandbox",
"search_id": "71498fa9-d3a7-4b6c-81bd-76693be726d1",
"status": "complete",
"hotels_details": [
{
"id": "hotel_nordbo_2",
"hid": 10048834,
"name": "Hotel Nordbo",
"kind": "Hotel",
"address": "Vandsovej 13, Nuuk, 3900, Greenland, Nuuk",
"latitude": 64.17923,
"longitude": -51.73019,
"postal_code": null,
"region": {
"id": 1359,
"country_code": "GL",
"iata": "GOH",
"name": "Nuuk",
"type": "City",
"type_v2": "city"
},
"star_rating": 0,
"images": [
"https://cdn.worldota.net/t/{size}/content/16/be/16be5aea51c0060686286cf8c886e4e07e1e5dce.jpeg",
"https://cdn.worldota.net/t/{size}/content/b1/98/b198dca0393650833ee449c3e460b2af85a04dda.jpeg"
],
"serp_filters": [
"has_parking",
"has_meal",
"has_pets"
],
"amenity_groups": [
{
"amenities": [
"24-hour reception",
"Smoke-free property",
"Ticket assistance"
],
"non_free_amenities": [],
"group_name": "General"
},
{
"amenities": [
"Breakfast",
"Restaurant"
],
"non_free_amenities": [],
"group_name": "Meals"
}
]
},
{
"id": "hhe_express",
"hid": 9168363,
"name": "HHE Express Hotel",
"kind": "Hotel",
"address": "Aqqusinersuaq 14B, Nuuk",
"latitude": 64.17208,
"longitude": -51.73649,
"postal_code": "3900",
"region": {
"id": 1359,
"country_code": "GL",
"iata": "GOH",
"name": "Nuuk",
"type": "City",
"type_v2": "city"
},
"star_rating": 3,
"images": [
"https://cdn.worldota.net/t/{size}/content/b5/39/b539a20fd8349ef419e73802ced9a04215155205.JPEG",
"https://cdn.worldota.net/t/{size}/content/41/97/4197c95a76a3ada2539a0fe169e7e3d7df3e80f9.jpeg"
],
"serp_filters": [
"has_internet",
"has_parking"
],
"amenity_groups": [
{
"amenities": [
"24-hour reception",
"Elevator/lift",
"Smoke-free property"
],
"non_free_amenities": [],
"group_name": "General"
},
{
"amenities": [
"Free Wi-Fi"
],
"non_free_amenities": [],
"group_name": "Internet"
}
]
}
],
"processing_status": {
"total_hotels": 5,
"cached_hotels": 5,
"queued_hotels": 0
},
"queue_info": {
"queued_hotel_ids": [],
"estimated_completion": null
},
"timing": {
"total_duration": 0.84,
"search_duration": 0.82,
"cache_check_duration": 0.02
},
"hotels_pricing": {
"hotel_nordbo_2": {
"exchange_rate": 285,
"agency_currency": "DZD",
"agency_commission": 438.68,
"final_price": 219774.68,
"b2b_price": 219336
},
"hhe_express": {
"exchange_rate": 285,
"agency_currency": "DZD",
"agency_commission": 228.83,
"final_price": 114639.23,
"b2b_price": 114410.4
}
},
"missing_hotel_ids": [],
"missing_hotels_pricing": {}
}{
"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": [
"https://cdn.worldota.net/t/{size}/extranet/b5/d3/b5d3d33394494c68321246882c1bd93a6832dcd5.jpeg",
"https://cdn.worldota.net/t/{size}/extranet/15/44/15440558c952ec4c3488730d1563dc9e8d25832c.JPEG"
],
"serp_filters": [
"has_internet",
"has_parking",
"has_spa",
"has_pets",
"has_jacuzzi",
"kitchen"
],
"amenity_groups": [
{
"amenities": [
"24-hour reception",
"Early check-in",
"Late check-out"
],
"non_free_amenities": [],
"group_name": "General"
},
{
"amenities": [
"Concierge services",
"Dry-cleaning",
"Shoe shine"
],
"non_free_amenities": [
"Dry-cleaning",
"Shoe shine"
],
"group_name": "Services and amenities"
}
]
}
],
"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": {}
}{
"environment": "sandbox",
"search_id": "4a6877dc-96da-4f32-8c1b-4aaed8b60fe4",
"status": "partial",
"hotels_details": [
{
"id": "hotel_honduras_maya_6",
"hid": 6329711,
"name": "Hotel Honduras Maya",
"kind": "Hotel",
"address": "Colonia Palmira 3era calle ave, Tegucigalpa",
"latitude": 14.103492,
"longitude": -87.19721,
"postal_code": "11101",
"region": {
"id": 3421,
"country_code": "HN",
"iata": "TGU",
"name": "Tegucigalpa",
"type": "City",
"type_v2": "city"
},
"star_rating": 3,
"images": [
"https://cdn.worldota.net/t/{size}/content/1d/67/1d67eefb8685fb4b809624bb4f6c437592722183.JPEG",
"https://cdn.worldota.net/t/{size}/content/6a/0e/6a0ebfe39089a02e1e6da4a03eb6200047545ba1.JPEG"
],
"serp_filters": [
"has_internet",
"has_airport_transfer",
"has_parking",
"has_kids",
"has_pool"
],
"amenity_groups": [
{
"amenities": [
"ATM",
"Air conditioning",
"24-hour reception"
],
"non_free_amenities": [],
"group_name": "General"
},
{
"amenities": [
"Bridal suite",
"Room service",
"Interconnecting rooms available"
],
"non_free_amenities": [],
"group_name": "Rooms"
}
]
}
],
"processing_status": {
"total_hotels": 15,
"cached_hotels": 14,
"queued_hotels": 1
},
"queue_info": {
"queued_hotel_ids": [
"comfort_inn_tegucigalpa"
],
"estimated_completion": "about 9 minutes",
"estimated_completion_seconds": 541
},
"timing": {
"total_duration": 4.38,
"search_duration": 4.33,
"cache_check_duration": 0.05
},
"hotels_pricing": {
"hotel_honduras_maya_6": {
"exchange_rate": 285,
"agency_currency": "DZD",
"agency_commission": 285.14,
"final_price": 142853.54,
"b2b_price": 142568.4
},
"comfort_inn_tegucigalpa": {
"exchange_rate": 285,
"agency_currency": "DZD",
"agency_commission": 218.75,
"final_price": 109590.36,
"b2b_price": 109371.61
}
},
"missing_hotel_ids": [
"comfort_inn_tegucigalpa"
],
"missing_hotels_pricing": {
"comfort_inn_tegucigalpa": {
"exchange_rate": 285,
"agency_currency": "DZD",
"agency_commission": 218.75,
"final_price": 109590.36,
"b2b_price": 109371.61
}
}
}{
"environment": "sandbox",
"search_id": "0c3f0e0e-1f0b-4f55-a2a6-8d4f2f1d2d11",
"status": "no_hotels_found",
"hotels_details": [],
"processing_status": {
"total_hotels": 0,
"cached_hotels": 0,
"queued_hotels": 0
},
"queue_info": {
"queued_hotel_ids": [],
"estimated_completion": null
},
"timing": {
"total_duration": 0.24,
"search_duration": 0.22,
"cache_check_duration": 0
}
}Request
Body
Required, JSON.
latitudenumberGeo search: the latitude of the center of the search, -90 to 90. Send it with longitude and radius; the coordinates of a place come from the locations search. A number written as text ("48.8566") is read as the number, with a coerced_value warning.
Between -90 and 90.
longitudenumberGeo search: the longitude of the center, -180 to 180. A number written as text ("2.3522") is read as the number, with a coerced_value warning.
Between -180 and 180.
radiusintegerGeo search: the radius around the center, in meters, 100 to 70,000. Required for a geo search; there is no default. A value outside the range is moved to the nearest bound and the answer carries a coerced_value warning. A number written as text ("3000") is read as the number, with a coerced_value warning.
Between 100 and 70000.
hotel_idstringSearch one hotel instead of the hotels around a point: its FX-Port id (1 to 128 characters: letters, digits and _ . : -; spaces around it are trimmed). A JSON integer is read as its text, but it is not looked up as the supplier's numeric hid here: send the FX-Port id. When it is sent, latitude, longitude and radius are ignored; a null hotel_id next to latitude and longitude is a geo search.
checkinstringrequiredCheck-in date, YYYY-MM-DD: from yesterday (for time zones) to 400 days ahead. A date written with a midnight time (2026-12-01T00:00:00Z) is read as that day, with a coerced_value warning; any other time of day is invalid_date.
checkoutstringrequiredCheck-out date, YYYY-MM-DD, after checkin. A stay is 1 to 30 nights. A midnight time is read as in checkin.
guestsarray of objectrequiredThe rooms: one {adults, children} object per room, 1 to 9 rooms.
ShowHide 2 attributes
adultsintegerrequiredNumber of adults in the room, 1 to 6. A number written as text ("2") is read as the number, with a coerced_value warning.
Between 1 and 6.
childrenarray of integerOne entry per child of the room: the age at check-in. [] or omitted when there is none. At most 4 children per room.
residencystringResidency of the guests, a two-letter ISO 3166-1 country code (gb, dz, fr). A sub-territory code of the website's nationality list (GB-SCT, USPR, ES-XCI, PT-MA, BQ-SA ...) is read as its country, with a coerced_value warning: send the 2-letter country. Some rates exist for some residencies only. Not defaulted: always send it.
languagestringLanguage of the supplier's answer, such as en, fr or zh_CN. A longer tag (zh-Hans-CN, es-419, sr-Latn-RS) is read as the supplier's code, with a coerced_value warning. The hotel content in the answer is English whatever you send.
Default en.
idstringdeprecatedLegacy name, still accepted. Use hotel_id instead.
The hotel id, in its older spelling. Use hotel_id.
hotelIdstringdeprecatedLegacy name, still accepted. Use hotel_id instead.
The hotel id, in its older spelling. Use hotel_id.
checkinDatestringdeprecatedLegacy name, still accepted. Use checkin instead.
The check-in date, in an older spelling. Use checkin.
checkin_datestringdeprecatedLegacy name, still accepted. Use checkin instead.
The check-in date, in an older spelling. Use checkin.
check_instringdeprecatedLegacy name, still accepted. Use checkin instead.
The check-in date, in an older spelling. Use checkin.
checkoutDatestringdeprecatedLegacy name, still accepted. Use checkout instead.
The check-out date, in an older spelling. Use checkout.
checkout_datestringdeprecatedLegacy name, still accepted. Use checkout instead.
The check-out date, in an older spelling. Use checkout.
check_outstringdeprecatedLegacy name, still accepted. Use checkout instead.
The check-out date, in an older spelling. Use checkout.
Response
200The hotels that are available, with their mini cards and prices. status tells how many have content; an empty hotels_details with no_hotels_found means no hotel is available for the request (also the case when a hotel exists but not for this residency). The examples are real answers of the sandbox: a geo search around Nuuk, a search of one hotel, a geo search around Tegucigalpa where one priced hotel has no card yet, and an empty answer.
environmentstringThe environment of the key that made the call: sandbox for fxp_test_ keys, live for fxp_live_ keys. Present in every JSON body.
One of sandbox, live.
request_idstringThe id of the request, also in the X-Request-Id header.
warningsarray of objectPresent only when the request used a previous spelling of a field or something the endpoint ignored.
ShowHide 5 attributes
codestringWhat the warning is about.
One of deprecated_field, ignored_field, coerced_value, deprecated_value, deprecated_endpoint.
fieldstringThe request field the warning is about.
replacementstringThe name to use instead, for deprecated_* warnings.
messagestringA sentence that says what happened and what to do.
documentation_urlstringWhere the naming rules are explained.
search_idstringThe id of the search, also in the X-Search-Id header. Quote it to support.
statusstringcomplete: every priced hotel has content. partial: some do not (see missing_hotel_ids). cache_miss: none has. no_hotels_found: no hotel is available for the request.
One of complete, partial, cache_miss, no_hotels_found.
hotels_detailsarray of HotelMiniThe mini card of each hotel that has cached content. No rates here: the prices are in hotels_pricing.
processing_statusobjectHow many hotels of the search have content.
ShowHide 3 attributes
total_hotelsintegerHotels the supplier priced for the search.
cached_hotelsintegerOf them, the hotels whose content FX-Port holds: they are in hotels_details.
queued_hotelsintegerOf them, the hotels without cached content that were queued for loading: their ids are in missing_hotel_ids.
queue_infoobjectThe hotels without cached content that FX-Port loads in the background.
ShowHide 3 attributes
queued_hotel_idsarray of stringThe ids of the hotels whose content was queued for loading (at most 50 per search).
estimated_completionstringnullableA rough delay until the content is loaded, such as about 9 minutes. null when nothing was queued.
estimated_completion_secondsintegerThe same delay in seconds. Present only when hotels were queued.
timingobjectWhere the time of a search went, in seconds.
ShowHide 3 attributes
total_durationnumberSeconds the whole search took, in FX-Port.
search_durationnumberSeconds the supplier took to price the hotels.
cache_check_durationnumberSeconds FX-Port took to read the hotel content.
hotels_pricingobjectThe price of the cheapest rate of every priced hotel, by hotel id. Absent when status is no_hotels_found.
missing_hotel_idsarray of stringThe ids of the hotels that are priced but have no cached content yet. Get one with get_hotel_info. Absent when status is no_hotels_found.
missing_hotels_pricingobjectThe price entry of each hotel of missing_hotel_ids, with the same fields as hotels_pricing.
truncatedbooleantrue when the supplier found more hotels than one search answers and the rest was cut off. Present only then: narrow the search.
max_hotelsintegerThe most hotels one search answers. Present with truncated.
total_hotels_foundintegerHow many hotels the supplier found before the cut. Present with truncated.
notestringA hint about an empty answer, for example that test_hotel has no availability for the residency you sent. Present only when there is one.
Errors
| Status | Code | Example message |
|---|---|---|
| 400 | stay_too_long | A stay can be at most 30 nights ('checkout' is 35 nights after 'checkin'). |
| 400 | missing_field | Missing required fields for hotel_id search: ['guests'] |
| 400 | missing_field | Missing required fields for hotel_id search: ['checkin', 'guests'] |
| 400 | bad_request | Do not pass 'currency'. Currency is resolved automatically from the authenticated agency. |
| 400 | missing_field | 'radius' (meters) is required for a geo search. |
| 400 | invalid_radius | 'radius' must be a whole number of meters. |
| 422 | supplier_rejected_request | The hotel supplier rejected the request parameters. Check dates, guests, residency and radius. |
| 503 | supplier_busy | The supplier is temporarily at capacity; retry after the time given in the Retry-After header. |
The shape of the error body depends on the endpoint. See Errors for every shape and code.