Price a flight offer
Confirm the current price and conditions of one offer of a search with its supplier, just before you book it.
/api/v1/flights/price_flightThis call is required before book_flight: an offer that was not priced is refused with 404 offer_not_priced. Send the searchId of the supplier entry the offer is in (suppliers[n].searchId, never the top-level requestId) and the id of the offer. The answer is the current version of the offer: its price can differ from the search, supportHold is final, and an Amadeus offer lists the extra bags that can be bought. Pricing reserves nothing.
A searchId is valid for 24 hours, but a supplier withdraws offers sooner (a Duffel offer lives 15 to 60 minutes): on 410 offer_expired, search again. A priced offer can be booked for 12 hours.
curl https://api.fx-port.com/api/v1/flights/price_flight \
-H "Authorization: Bearer fxp_test_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"search_id": "fs_dfx_a3aeaa36-74ad-424b-b88d-e6bdc9a4ba94",
"offer_id": "fx_offer_89d6592c"
}'{
"environment": "sandbox",
"success": true,
"requestId": "76f8fc58",
"offerId": "fx_offer_89d6592c",
"offerType": "priced",
"processingTime": 0.177,
"supplierCurrency": "USD",
"agencyCurrency": "DZD",
"results": {
"totalOffers": 1,
"supplierCurrency": "USD",
"agencyCurrency": "DZD",
"offers": [
{
"id": "fx_offer_89d6592c",
"type": "flight_offer",
"supplier": {
"id": "duffel_1",
"name": "Duffel",
"originalId": "off_034q6JKduVe2mSW1fH8lge"
},
"source": "duffel",
"bookableSeats": null,
"supportHold": false,
"supportVoid": false,
"voidDeadline": null,
"filtersApplied": {},
"warnings": [],
"instantTicketingRequired": false,
"pricing": {
"supplierCurrency": "USD",
"agencyCurrency": "DZD",
"basePrice": 16975,
"taxesAndFees": 5366.8,
"agencyCommission": 22.35,
"finalPrice": 22364.15,
"b2bPrice": 22341.8,
"additionalServices": []
},
"itinerary": [
{
"direction": "outbound",
"duration": "PT2H24M",
"stops": 0,
"segments": [
{
"id": "seg_0000BC0a5iVGdVLqUATqqr",
"departure": {
"airportCode": "ALG",
"airportName": "Houari Boumediene Airport",
"cityName": "Algiers",
"countryCode": "DZ",
"terminal": "2",
"datetime": "2026-12-15T10:50:00",
"timeZone": "Africa/Algiers"
},
"arrival": {
"airportCode": "CDG",
"airportName": "Paris Charles de Gaulle Airport",
"cityName": "Paris",
"countryCode": "FR",
"terminal": "1",
"datetime": "2026-12-15T13:14:00",
"timeZone": "Europe/Paris"
},
"flight": {
"carrierCode": "BA",
"carrierName": "British Airways",
"carrierLogoUrl": "https://assets.duffel.com/img/airlines/for-light-background/full-color-logo/BA.svg",
"flightNumber": "0107",
"aircraftCode": null,
"aircraftName": null,
"operatingCarrier": "BA",
"operatingCarrierName": "British Airways"
},
"duration": "PT2H24M",
"cabin": "ECONOMY",
"bookingClass": null,
"fareBasis": "Y20LGTN2",
"brandedFare": "Basic",
"brandedFareLabel": "Basic"
}
],
"conditions": {
"changeBeforeDeparture": {
"allowed": true
},
"refundBeforeDeparture": {
"allowed": true
}
}
}
],
"travelerPricing": [
{
"travelerId": "pas_0000BC0a5iH5UE0bmBqWkl",
"travelerType": "ADULT",
"fareOption": "STANDARD",
"price": {
"supplierCurrency": "USD",
"agencyCurrency": "DZD",
"base": 16975,
"total": 22364.15,
"b2bPrice": 22341.8
},
"fareDetailsBySegment": [
{
"segmentId": "seg_0000BC0a5iVGdVLqUATqqr",
"cabin": "ECONOMY",
"fareBasis": "Y20LGTN2",
"brandedFare": "Basic",
"brandedFareLabel": "Basic",
"bookingClass": "Economy",
"includedCheckedBags": {
"quantity": 1
},
"includedCabinBags": {
"quantity": 1
},
"amenities": []
}
]
}
],
"conditions": {
"refundBeforeDeparture": {
"allowed": true
},
"changeBeforeDeparture": {
"allowed": true
}
},
"fareRules": {
"refund": {
"allowed": true
},
"exchange": {
"allowed": true
},
"supplierCurrency": "USD",
"agencyCurrency": "DZD"
},
"validatingAirline": [
{
"code": "BA",
"name": "British Airways"
}
],
"additionalServices": {
"baggage": [
{
"id": "ase_0000BC0aGG1cCZZ8LCieTb",
"type": "checked",
"quantity": 1,
"maxQuantity": 1,
"maxWeightKg": 23,
"maxWeightUnit": "kg",
"priceAmount": 20,
"convertedPriceAmount": 5000,
"priceCurrency": "USD",
"applicablePassengers": [
"pas_0000BC0a5iH5UE0bmBqWkl"
],
"applicableSegments": [
"seg_0000BC0a5iVGdVLqUATqqr"
],
"bookableByItinerary": false,
"metadata": {
"name": "CHECKED",
"description": "Additional checked"
}
}
]
}
}
]
},
"exchangeRate": 250
}{
"environment": "sandbox",
"success": true,
"requestId": "6d05c5ff",
"offerId": "fx_offer_5d3add32",
"offerType": "priced",
"processingTime": 1.441,
"supplierCurrency": "DZD",
"agencyCurrency": "DZD",
"results": {
"totalOffers": 1,
"supplierCurrency": "DZD",
"agencyCurrency": "DZD",
"offers": [
{
"id": "fx_offer_5d3add32",
"type": "flight_offer",
"supplier": {
"id": "amadeus_aqc_dz_1",
"name": "Amadeus Algeria",
"originalId": "5"
},
"source": "GDS",
"bookableSeats": 9,
"supportHold": true,
"supportVoid": true,
"voidDeadline": "2026-11-01T23:00:00Z",
"filtersApplied": {},
"warnings": [],
"instantTicketingRequired": false,
"pricing": {
"supplierCurrency": "DZD",
"agencyCurrency": "DZD",
"basePrice": 19470,
"taxesAndFees": 10376.96,
"agencyCommission": 29.85,
"finalPrice": 29876.81,
"b2bPrice": 29846.96,
"additionalServices": [],
"acd": {
"applied": false
}
},
"itinerary": [
{
"direction": "outbound",
"duration": "PT2H35M",
"stops": 0,
"segments": [
{
"id": "43",
"departure": {
"airportCode": "ALG",
"airportName": "Houari Boumediene Airport",
"cityName": "Algiers",
"countryCode": "DZ",
"terminal": "4",
"datetime": "2026-12-15T18:40:00",
"timeZone": "Africa/Algiers"
},
"arrival": {
"airportCode": "CDG",
"airportName": "Paris Charles de Gaulle Airport",
"cityName": "Paris",
"countryCode": "FR",
"terminal": "2E",
"datetime": "2026-12-15T21:15:00",
"timeZone": "Europe/Paris"
},
"flight": {
"carrierCode": "AF",
"carrierName": "Air France",
"carrierLogoUrl": "https://assets.duffel.com/img/airlines/for-light-background/full-color-logo/AF.svg",
"flightNumber": "1655",
"aircraftCode": "223",
"aircraftName": "223",
"operatingCarrier": "AF",
"operatingCarrierName": "Air France"
},
"duration": "PT2H35M",
"cabin": "ECONOMY",
"bookingClass": "X",
"fareBasis": "XYS0BCSA",
"brandedFare": "STANDARD",
"brandedFareLabel": "STANDARD"
}
],
"conditions": {
"changeBeforeDeparture": {
"allowed": true
},
"refundBeforeDeparture": {
"allowed": false
}
}
}
],
"travelerPricing": [
{
"travelerId": "1",
"travelerType": "ADULT",
"fareOption": "STANDARD",
"price": {
"supplierCurrency": "DZD",
"agencyCurrency": "DZD",
"base": 19470,
"total": 29876.81,
"b2bPrice": 29846.96
},
"fareDetailsBySegment": [
{
"segmentId": "43",
"cabin": "ECONOMY",
"fareBasis": "XYS0BCSA",
"brandedFare": "STANDARD",
"brandedFareLabel": "STANDARD",
"bookingClass": "X",
"includedCheckedBags": {
"quantity": 1
},
"includedCabinBags": {
"quantity": 1
},
"amenities": []
}
]
}
],
"conditions": {
"refundBeforeDeparture": {
"allowed": false
},
"changeBeforeDeparture": {
"allowed": true
}
},
"fareRules": {
"exchange": {
"allowed": true
},
"refund": {
"allowed": false
},
"revalidation": {
"allowed": false
},
"supplierCurrency": "DZD",
"agencyCurrency": "DZD"
},
"validatingAirline": [
{
"code": "AF",
"name": "Air France"
}
],
"additionalServices": {
"baggage": [
{
"id": "bag_service_1",
"type": "checked",
"quantity": 1,
"maxQuantity": 1,
"maxWeightKg": null,
"maxWeightUnit": null,
"priceAmount": 8347,
"convertedPriceAmount": 8347,
"priceCurrency": "DZD",
"applicablePassengers": [
"1"
],
"applicableSegments": [
"43"
],
"bookableByItinerary": true,
"metadata": {
"name": "CHECKED_BAG",
"description": "1 additional checked bag(s)"
}
}
]
}
}
]
}
}Request
Body
Required, JSON.
search_idstringrequiredThe searchId of the supplier entry the offer is in (suppliers[n].searchId), never the top-level requestId.
offer_idstringrequiredThe id of the offer.
agency_idstringNot needed: the agency of a call is always the one of your API key. The field is accepted so that older clients keep working, and it is ignored.
searchIdstringdeprecatedLegacy name, still accepted. Use search_id instead.
The previous spelling of search_id: The searchId of the supplier entry the offer is in (suppliers[n].searchId), never the top-level requestId.
offerIdstringdeprecatedLegacy name, still accepted. Use offer_id instead.
The previous spelling of offer_id: The id of the offer.
agencyIdstringdeprecatedLegacy name, still accepted. Use agency_id instead.
The previous spelling of agency_id: Not needed: the agency of a call is always the one of your API key.
Response
200The priced offer in results.offers[0]: the price to book, supportHold and, for Amadeus, the bags that can be added.
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.
successbooleantrue when the offer was priced.
requestIdstringdeprecatedLegacy name, still accepted. Use request_id instead.
The id of this request, 8 characters, for support.
offerIdstringdeprecatedLegacy name, still accepted. Use offer_id instead.
The id of the priced offer.
offer_idstringThe id of the priced offer. The snake_case twin of offerId, with the same value: use this name.
offerTypestringAlways priced.
Always priced.
processingTimenumberdeprecatedLegacy name, still accepted. Use processing_time instead.
Seconds spent.
processing_timenumberSeconds spent. The snake_case twin of processingTime, with the same value: use this name.
supplierCurrencystringCurrency in which the supplier prices.
agencyCurrencystringCurrency of your agency.
resultsobjectThe priced offer.
ShowHide 4 attributes
totalOffersintegerAlways 1.
supplierCurrencystringCurrency in which the supplier prices.
agencyCurrencystringCurrency of your agency.
offersarray of FlightOfferThe priced offer.
exchangeRatenumberdeprecatedLegacy name, still accepted. Use exchange_rate instead.
Only when the supplier's currency is not your agency's.
exchange_ratenumberOnly when the supplier's currency is not your agency's. The snake_case twin of exchangeRate, with the same value: use this name.
Errors
| Status | Code | Example message |
|---|---|---|
| 400 | bad_request | Missing required parameters: search_id and offer_id are required |
| 400 | invalid_identifier | `search_id` is not a valid identifier (letters, digits and - _ . : = ~ only, up to 128 characters). |
| 404 | SEARCH_EXPIRED_OR_NOT_FOUND | Search ID 'fs_does_not_exist' not found or has expired |
| 404 | OFFER_NOT_FOUND_IN_SEARCH | Offer ID 'fx_offer_00000000' not found in search results |
| 410 | OFFER_EXPIRED | This offer has expired or is no longer available |
| 503 | supplier_temporarily_unavailable | Supplier 'duffel_1' circuit breaker is open: retry in a few moments. |
| 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.