# Price a flight offer

> Confirm the current price and conditions of one offer of a search with its supplier, just before you book it.

Endpoint: `POST /flights/price_flight`

Source: https://fx-port.com/docs/api/price-flight

`POST /api/v1/flights/price_flight`

Requires an API key with **Read** permission; a **Read+Write** key works too.

This 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.

## Request

### Body

Required, JSON.

- `search_id` (string, required): The `searchId` of the **supplier entry** the offer is in (`suppliers[n].searchId`), never the top-level `requestId`.
- `offer_id` (string, required): The `id` of the offer.
- `agency_id` (string, optional): Not 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.
- `searchId` (string, deprecated, optional): Legacy name: use `search_id`. The previous spelling of `search_id`: The `searchId` of the **supplier entry** the offer is in (`suppliers[n].searchId`), never the top-level `requestId`.
- `offerId` (string, deprecated, optional): Legacy name: use `offer_id`. The previous spelling of `offer_id`: The `id` of the offer.
- `agencyId` (string, deprecated, optional): Legacy name: use `agency_id`. The previous spelling of `agency_id`: Not needed: the agency of a call is always the one of your API key.

### Example request

```bash
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"
}'
```

## Response

### 200: The priced offer in `results.offers[0]`: the price to book, `supportHold` and, for Amadeus, the bags that can be added.

- `environment` (string): The 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_id` (string): The id of the request, also in the `X-Request-Id` header.
- `warnings` (array of object): Present only when the request used a previous spelling of a field or something the endpoint ignored.
  - `code` (string): What the warning is about. One of `deprecated_field`, `ignored_field`, `coerced_value`, `deprecated_value`, `deprecated_endpoint`.
  - `field` (string): The request field the warning is about.
  - `replacement` (string): The name to use instead, for `deprecated_*` warnings.
  - `message` (string): A sentence that says what happened and what to do.
  - `documentation_url` (string): Where the naming rules are explained.
- `success` (boolean): `true` when the offer was priced.
- `requestId` (string, deprecated): Legacy name: use `request_id`. The id of this request, 8 characters, for support.
- `offerId` (string, deprecated): Legacy name: use `offer_id`. The `id` of the priced offer.
- `offer_id` (string): The `id` of the priced offer. The snake_case twin of `offerId`, with the same value: use this name.
- `offerType` (string): Always `priced`. Always `priced`.
- `processingTime` (number, deprecated): Legacy name: use `processing_time`. Seconds spent.
- `processing_time` (number): Seconds spent. The snake_case twin of `processingTime`, with the same value: use this name.
- `supplierCurrency` (string): Currency in which the supplier prices.
- `agencyCurrency` (string): Currency of your agency.
- `results` (object): The priced offer.
  - `totalOffers` (integer): Always 1.
  - `supplierCurrency` (string): Currency in which the supplier prices.
  - `agencyCurrency` (string): Currency of your agency.
  - `offers` (array of FlightOffer): The priced offer.
- `exchangeRate` (number, deprecated): Legacy name: use `exchange_rate`. Only when the supplier's currency is not your agency's.
- `exchange_rate` (number): Only when the supplier's currency is not your agency's. The snake_case twin of `exchangeRate`, with the same value: use this name.

```json
{
  "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
}
```

## 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. |

See [Errors](https://fx-port.com/docs/errors.md) for every code and how to react.

## Related guides

- [Price a flight offer](https://fx-port.com/docs/flights/price.md)
- [Flight pricing](https://fx-port.com/docs/flights/pricing.md)
- [Search flights](https://fx-port.com/docs/flights/search.md)
