Getting An Accurate Price Before Booking

About

This guide shows you how to calculate and display an accurate price for a flight before payment, regardless of payment method, ensuring full price transparency throughout the booking flow.
There are two instances when this is especially important in the Duffel API:
  • Credit card surcharges are additional fees charged by the supplier, in this case the airline, for processing a certain card. They are often applied to corporate credit cards.

  • When the airline may charge in a different currency depending on the payment method used.

Overview

The Duffel API provides endpoints to determine these prices at both the offer and order stages, ensuring customers see the accurate total price including any fees before completing their purchase.
Key Benefits:
  • Calculate price, inclusive of surcharges, before payment collection

  • Maintain price transparency throughout the booking flow

  • Support for both instant and hold order workflows

Implementation Workflows

Instant Order Flow

For immediate payment and booking confirmation:
  • Search for offers

  • Price offer with payment method

  • Display total with surcharge

  • [Optional] (Re)price offer with payment method

  • Create instant order with payment

Hold Order Flow

For holding a space before payment:
  • Search for offers

  • Create hold order

  • Price order with payment method

  • Display total with surcharge

  • [Optional] (Re)price with a different payment method

  • Complete payment

Pre-requisites

Create a Payment Card

Follow the Paying with customer cards guide to learn about creating cards.

Caution

Making an Order

Price an Offer with a payment method

Before creating an order, calculate the total price including any surcharges:

Request

Shell

curl -X PATCH --compressed "https://api.duffel.com/air/offers/$OFFER_ID/actions/price" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Content-Type: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer $YOUR_ACCESS_TOKEN" \
-d '{
"data": {
"intended_payment_methods": [
{ "type": "card", "card_id": "tcd_00009hthhsUZ8W4LxQgkjb" }
],
"intended_services": [
{ "quantity": 1, "id": "ase_00009hj8USM7Ncg31cB123" }
]
}}'

Response

JSON

{
"data": {
"id": "off_00009hthhsUZ8W4LxQgkjb",
"total_amount": "300.00",
"total_currency": "USD"
"intended_payment_methods": [
{
"type": "card",
"card_id": "tcd_00009hthhsUZ8W4LxQgkjb",
"surcharge_amount": "1.57",
"surcharge_currency": "USD"
}
],
"intended_services": [
{ "quantity": 1, "id": "ase_00009hj8USM7Ncg31cB123" }
]
}
// ...
}
In this example, the total charged to the card would be 301.57USD as that is the total of the fare plus the surcharge applied.

Note

If multiple requests are made to this endpoint for the same offer, the offer will represent the price for the last intended_payment_methods provided.

Note

Create the Order

Option A: Order with Instant Payment

Create and pay for the order in a single request:

Shell

curl -X POST --compressed "https://api.duffel.com/air/orders" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer $YOUR_ACCESS_TOKEN" \
-d '{
"data": {
"selected_offers": ["$OFFER_ID$"],
"payments": [
{
"three_d_secure_session_id": "3ds_0000AWr2XsTR1F1Vp34gh5",
"currency": "USD",
"amount": "301.57"
}
],
"services": [
{ "quantity": 1, "id": "ase_00009hj8USM7Ncg31cB123" }
],
"type": "instant",
"passengers": [
// ... passenger details
]
}}'

Caution


Caution

intended_payment_methods will not be persisted on the paid order.

Option B: Hold Order for Later Payment

Create a hold order without immediate payment:

Shell

curl -X POST --compressed "https://api.duffel.com/air/orders" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer $YOUR_ACCESS_TOKEN" \
-d '{
"data": {
"selected_offers": ["off_00009hthhsUZ8W4LxQgkjb"],
"type": "hold",
"services": [
{ "quantity": 1, "id": "ase_00009hj8USM7Ncg31cB123" }
],
"passengers": [
// ... passenger details
]
}}'

Working with Hold Orders

Pricing a Hold Order

For unpaid hold orders, attach or update the payment method to see the final price:

Shell

curl -X PATCH --compressed "https://api.duffel.com/air/$ORDER_ID/actions/price" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer $YOUR_ACCESS_TOKEN" \
-d '{
"data": {
"intended_payment_methods": [
{ "type": "card", "card_id": "tcd_00009hthhsUZ8W4LxQgkjb" }
]
}}'
If the offer was priced with intended_payment_methods and a subsequent hold order is priced with different intended_payment_methods, the price will represent the correct price for the intended_payment_methods that were supplied last.

Note


Note

Completing Payment

Complete the payment for a hold order:

Shell

curl -X POST --compressed "https://api.duffel.com/air/orders/$ORDER_ID/payment" \
-H "Accept-Encoding: gzip" \
-H "Accept: application/json" \
-H "Duffel-Version: v2" \
-H "Authorization: Bearer $YOUR_ACCESS_TOKEN"
-d '{
"data": {
"payments": [
{
"three_d_secure_session_id": "3ds_0000AWr2XsTR1F1Vp34gh5",
"currency": "USD",
"amount": "301.57"
}
]
}}'

Caution


Caution

Surcharges will not be persisted on the paid order.

Best Practises

Display Transparency

  • Show the fare and surcharge separately

  • Update the displayed total after pricing with a payment method

  • Make it clear that the surcharge is often considered non-refundable by the supplier

  • Display the final currency clearly, as this may change based on payment method

Testing your integration

When providing a card within intended_payment_methods to price either a Duffel Airways offer or order, you will be returned a non-zero surcharge_amount to allow you to test how you application reacts to this.

Error Handling

  • Handle card expiry errors gracefully by creating new card resources and re-pricing

  • Validate that payment methods and services match between pricing and payment requests

  • Monitor for currency changes when pricing with different payment methods

  • invalid_intended_card error code 422 error response can be returned if the card record used as the intended payment method has expired. This error can also be returned from the GET /air/offers/:id, GET /air/seat_maps and PATCH /air/offers/:offer_id/passengers endpoints as those endpoints will price the offer from the last intended payment methods.

Card Management

  • Create card resources as close to payment time as possible to minimize expiry issues

  • Implement retry logic for card expiry scenarios

Keep Learning

Where to go from here?