Choosing your search response format
Overview
offers(the default) — a flat list of offers, each containing the full slice, segment, airline, and airport data inline. This is the shape you already know.itineraries— offers grouped into a hierarchy of slices, itineraries, and fare brands, with airlines, places, and aircraft pulled out into shared reference maps.
itineraries shape is also significantly more condensed over the wire than the flat offers shape — often several times smaller for a typical return search. If payload size is a concern for your integration, this is a meaningful win on top of the UI benefits.What do you need to start?
Requesting a response shape
view=offers or view=itineraries to any of the offer request endpoints:POST /air/offer_requestsGET /air/offer_requests/:idGET /air/batch_offer_requests/:id
offers shape so existing integrations are unaffected.Shell
curl -X POST --compressed "https://api.duffel.com/air/offer_requests?view=itineraries"-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": {"cabin_class": "economy","passengers": [{ "type": "adult" }],"slices": [{"origin": "NYC","destination": "LON","departure_date": "2026-12-15"},{"origin": "LON","destination": "NYC","departure_date": "2026-12-20"}]}}'
Comparing the two shapes
view=offers (default)
offers array. Airlines, places, and aircraft are embedded inline on every segment. Best for integrations that treat each offer as an opaque unit and don't need to group the UI around shared itineraries.view=itineraries
slices[]— one entry per slice in the request.slices[].itineraries[]— offers sharing the exact same flight segments (same flights, same order, same cabins).slices[].itineraries[].brands[]— fare brands available on that itinerary (cabin, baggage, change/refund conditions).slices[].itineraries[].brands[].offers[]— the priced offers within that brand.
references maps rather than repeated inline.JSON
{"data": {"id": "orq_00009hthhsUZ8W4LxQghdf","references": {"airlines": {"arl_00009VME7D6ivUu8dn35WK": {"name": "Duffel Airways","iata_code": "ZZ"}},"places": { "arp_jfk_us": { "iata_code": "JFK", "type": "airport" } },"aircraft": {"arc_00009VMF8AhXSSRnQDI6HE": {"name": "Airbus A380","iata_code": "380"}}},"slices": [{"origin": "arp_jfk_us","destination": "arp_lhr_gb","itineraries": [{"segments": [/* shared flight segments, carriers and places as references */],"brands": [{"fare_brand_name": "Economy Basic","offers": [{"id": "off_00009htYpSCXrwaB9Dn456","type": "single_ticket","owner": "arl_00009VME7D6ivUu8dn35WK","total_amount": "470.00","total_currency": "GBP"}]}]}]}]}}
Which one should I use?
If your UI shows a single list of offers and you don't need shared-itinerary grouping, stay on
view=offers— nothing to change.If you want to present results grouped by itinerary and fare brand, if you want smaller responses over the wire, or if you want to offer split-ticket itineraries to your customers, use
view=itineraries.
The type field on offers
itineraries shape, every offer carries a type:single_ticket— a normal offer from a single airline covering all of the requested slices. This is what you already receive today.split_ticket— a one-way offer that is part of a split-ticket combination. These only appear when split-ticket itineraries are enabled on the request.
single_ticket.