Exports

Every file is generated from the same data as this site. Open a strip to read it here, or download it. sample until the API shape is frozen

▸Postman collectionairiq-flight-api.postman_collection.json · 143 KBDownload

Import into Postman. Fill api_key in the environment and run the Flow folder top to bottom: every call stores the ids the next one needs. The Test cases folder holds the real captured requests.

▾{3 keys}
▾"info": {3 keys}
"name": "AirIQ Flight API"
"description": "SAMPLE: generated from the documentation data before the API shape is frozen; regenerated after.\n\nFill api_key in the environment, run the Flow folder top to bottom: each call stores the ids the next one needs."
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
▾"variable": [7 items]
▸0: {2 keys}
▸1: {2 keys}
▸2: {2 keys}
▸3: {2 keys}
▸4: {2 keys}
▸5: {2 keys}
▸6: {2 keys}
▾"item": [2 items]
▸0: {3 keys}
▸1: {3 keys}
▸Postman environment: UATairiq-uat.postman_environment.json · 1 KBDownload

base_url of the test environment and an empty api_key.

▾{3 keys}
"name": "AirIQ uat"
▾"values": [2 items]
▸0: {3 keys}
▸1: {4 keys}
"_postman_variable_scope": "environment"
▸Postman environment: productionairiq-production.postman_environment.json · 1 KBDownload

base_url of production and an empty api_key.

▾{3 keys}
"name": "AirIQ production"
▾"values": [2 items]
▸0: {3 keys}
▸1: {4 keys}
"_postman_variable_scope": "environment"
▸OpenAPI 3airiq-flight-api.openapi.json · 72 KBDownload

For client code generators and API tools (Swagger UI, Insomnia, Stoplight).

▾{5 keys}
"openapi": "3.0.3"
▾"info": {3 keys}
"title": "AirIQ Flight API"
"version": "1.0.0-sample"
"description": "SAMPLE: generated from the documentation data before the API shape is frozen; regenerated after."
▾"servers": [2 items]
▸0: {2 keys}
▸1: {2 keys}
▾"paths": {9 keys}
▸"/generate-token": {1 key}
▸"/flights/search": {1 key}
▸"/flights/reprice": {1 key}
▸"/flights/ancillaries": {1 key}
▸"/flights/seat-map": {1 key}
▸"/flights/book": {1 key}
▸"/flights/booking/details": {1 key}
▸"/flights/booking/confirm-hold": {1 key}
▸"/flights/booking/release": {1 key}
▾"components": {2 keys}
▸"securitySchemes": {1 key}
▸"schemas": {1 key}
▸All test cases (zip)airiq-flight-api-test-cases.zip · 3131 KBDownload

Every test case in its own folder (01-domestic-oneway-1a/, …), with each step's request and response as numbered files (01-search-request.json, 01-search-response.json, …) and case.json: the case's title, description and steps in order. Replay a case top to bottom with your own token.

▸Integration guide (Markdown)airiq-flight-api-integration.md · 96 KBDownload

Everything on this site in one file: flow, authentication, every endpoint with request and reply, keys, errors, questions and the test cases. Give it to a developer, or to a coding assistant, as the plan for the integration.

# AirIQ Flight API: integration guide

_SAMPLE: generated from the documentation data before the API shape is frozen; regenerated after._

Generated from the same data as the documentation site.

## The flow

0. **Partner system**: has an API key
1. **1 generate-token**: api_key → bearer token, 4 hours
2. **2 search**: segments, passengers → option_id, price_id
3. **3 reprice**: items → itinerary_id, requirements, price
4. **4 ancillaries · 5 seat map**: optional, by itinerary_id
5. **6 book**: passengers, ancillaries, GST; pay or hold
6. **7 details**: status, PNR, tickets

Hold branch: **6 book is_hold=true** (status ONHOLD, pay_till) → **8 confirm-hold** (pay from your wallet, ticket → SUCCESS) → **9 release** (give the PNR back → PNR_RELEASED)

## Authentication

1. Your account manager gives you an API key (`aiqo_…`). Keep it on your server only.
2. Exchange it for a bearer token with `POST /generate-token`; it lasts 4 hours.
3. Send `Authorization: Bearer <token>` on every other call.

## Environments

- uat: `https://api.uat.airiqtech.com`
- production: `https://api.airiqtech.com`

## Endpoints

### 1. `POST /generate-token`

Exchange the API key for a token that lives 4 hours (expires_in 14400). Every later call sends it as Authorization: Bearer <token>.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "api_key": "ak_3f2e1d0c9b8a7f6e5d4c3b2a1f0e9d8c"
}
```


Reply:

```json
{
  "token": "<token>",
  "token_type": "Bearer",
  "expires_in": 14400,
  "expires_at": "2026-10-16T10:12:00Z"
}
```


Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `api_key` | string | required | must | Your API key (starts with aiqo_). Keep it on your server; never send it from a browser or app. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `token` | string | always | must | Send it as Authorization: Bearer <token> on every other call. |
| `token_type` | string | always | info | Always Bearer. |
| `expires_in` | integer | always | must | Seconds the token lives (14400 = 4 hours). Get a new token before it ends; a call with an expired token answers 401. |
| `expires_at` | datetime | always | useful | The same end as a time (UTC). |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid api_key) | Unknown key, suspended user, or the API has no API-key routes (today). Observed on the local stack. |
| 401 | 9001 | Authentication required (Api_key required) |  |
| 400 | 5000 | Invalid request ((Huma's text)) | Malformed JSON or wrong content type. |
| 429 | 9004 | Too many requests | Rate limit, when configured. |

Questions developers ask:

- **How long does a token last?** 4 hours (expires_in, expires_at). Renew before it ends; an expired token answers 401 with code 9001.
- **Can I call the API from a browser or a mobile app?** No. The API key must stay on your server; call the API from there.

### 2. `POST /flights/search`

One request, complete results: options grouped by the journeys their fares cover, each fare priced once for the whole option with a journey view; the per-flight segment view on request. The UI uses the streaming route instead; this one waits for all suppliers.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "segments": [
    {
      "from": "BLR",
      "to": "BOM",
      "date": "2026-11-14"
    }
  ],
  "adult": 1,
  "child": 0,
  "infant": 0,
  "cabin_class": 1,
  "fare_types": [
    1
  ],
  "direct_flight": false,
  "preferred_airlines": [
    "QP"
  ],
  "detail": "journey",
  "include_fare_rules": true
}
```

- detail: journey (default) = one set of fare attributes per fare option; segment = also segments[] inside each fare option, one entry per flight. Any other value is a 400 (field detail, rule one_of).
- include_fare_rules: default true; false leaves fare_rules out of the reply and off every fare.
- segments: 1 to 6 legs; a return trip is two segments. date is YYYY-MM-DD.
- adult 1-9 (required), child 0-9, infant 0-9.
- cabin_class: 1 economy, 2 premium economy, 3 business, 4 first; 0 or absent = no filter.
- fare_types: 1 regular, 2 student, 3 senior citizen, 4 doctor/nurse, 5 armed forces; absent = regular.

Reply:

```json
{
  "search_id": "a1d2c3b4-5e6f-4a7b-8c9d-0e1f2a3b4c5d",
  "status": "completed",
  "valid_till": "2026-10-18T21:12:00+05:30",
  "fare_rules": {
    "fr_1": {
      "cancellation": [
        {
          "allowed": false,
          "from": {
            "value": 0,
            "unit": "HOURS"
          },
          "to": {
            "value": 3,
            "unit": "HOURS"
          },
          "text": "Non-refundable within 3 hours of departure"
        },
        {
          "allowed": true,
          "amount": 3899,
          "from": {
            "value": 3,
            "unit": "HOURS"
          },
          "to": {
            "value": 365,
            "unit": "DAYS"
          }
        }
      ],
      "date_change": [
        {
          "allowed": true,
          "amount": 2999,
          "from": {
            "value": 3,
            "unit": "HOURS"
          },
          "to": {
            "value": 365,
            "unit": "DAYS"
          }
        }
      ]
    }
  },
  "results": [
    {
      "journey_indexes": [
        0
      ],
      "options": [
        {
          "option_id": "3f9e8d7c-6b5a-4f3e-9d2c-1b0a9f8e7d6c",
          "segments": [
            {
              "segment_index": 0,
              "journey_index": 0,
              "segment_id": "BLR_BOM_QP_1101",
              "from": "BLR",
              "to": "BOM",
              "airline_code": "QP",
              "airline_name": "Akasa Air",
              "aircraft_type": "737 MAX 8",
              "flight_number": "1101",
              "departure_time": "2026-11-14T06:00:00",
              "departure_terminal": "1",
              "arrival_time": "2026-11-14T07:45:00",
              "arrival_terminal": "2",
              "duration": 105
            }
          ],
          "fare_options": [
            {
              "price_id": "7c1b2f3e-9a4d-4c2e-8f1a-2b3c4d5e6f70",
              "fare_rules": {
                "0": "fr_1"
              },
              "adult": {
                "fare_ref": "SAVER",
                "refundable_type": "PARTIALLY_REFUNDABLE",
                "cabin_class": "Economy",
                "booking_class": "Q",
                "fare_basis": "QPSAVER",
                "baggage": {
                  "hand": {
                    "kg": 7
                  },
                  "checkin": {
                    "kg": 15
                  }
                },
                "fare": {
                  "hand_baggage": "7Kg",
                  "checkin_baggage": "15Kg",
                  "base_fare": 4200.0,
                  "yq": 0.0,
                  "yr": 0.0,
                  "airline_gst": 0.0,
                  "booking_fee": 0.0,
                  "commission": 0.0,
                  "other_taxes": 812.0,
                  "total_fare": 5012.0,
                  "net_fare": 5012.0,
                  "pax_count": 1
                }
              },
              "varies_by_segment": false
            }
          ]
        }
      ]
    }
  ]
}
```

- results[] groups options by the journey indexes their fares cover: one way = one group [0]; a return sold per direction = groups [0] and [1]; a combined return fare = one group [0, 1]. Pick one option and one fare per group until every requested journey is covered.
- option_id identifies the flights, price_id the fare on them; both go to /flights/reprice. Ids are valid until valid_till (60 minutes).
- A fare prices the whole option: one object per requested passenger type (adult, child, infant), each with its fare (base, taxes, total, net, pax_count), booking_class, fare_basis and baggage. No amount appears anywhere else, never inside segments[].
- Segment view (detail=segment): segments[] on every fare, one entry per flight matched by segment_index, same fields per flight.
- fare_rules on a fare maps each journey index to an id (fr_1, fr_2, …) in the top-level fare_rules; a missing index has no rule known at search. Ids mean nothing outside this reply.
- Baggage is {kg} and/or {pieces}; absent = not included or not known. Flight segments carry airport codes only (from, to).
- Times are local to the airport, format YYYY-MM-DDTHH:MM:SS, no zone; valid_till carries its offset.
- A missing field is zero, false or not applicable. The reply has no $schema field.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `segments[]` | array | required, 1 to 6 | must | The legs you search: one for one way, two for a return (second from the destination back), up to six for a multi-city trip. |
| `segments[].from` | string | required | must | Departure airport, IATA code. |
| `segments[].to` | string | required | must | Arrival airport, IATA code. |
| `segments[].date` | date | required | must | Departure date, YYYY-MM-DD, local to the departure airport. |
| `adult` | integer | required, 1 to 9 | must | Adults travelling. child and infant default to 0; an infant needs an adult. |
| `cabin_class` | integer | optional | useful | 1 economy (default), 2 premium economy, 3 business, 4 first. |
| `detail` | string | optional | useful | journey (default) or segment. segment adds segments[] inside every fare option with the fare attributes per flight. |
| `include_fare_rules` | boolean | optional, default true | info | false leaves fare_rules out of the reply and off every fare; smaller reply. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `search_id` | string | always | info | Id of this search, for support questions. |
| `valid_till` | datetime | always | must | Until when an option_id and price_id of this reply can be sent to reprice. After it, search again. |
| `fare_rules` | object | unless include_fare_rules is false | useful | Every distinct fare rule of the reply keyed by id (fr_1, fr_2, …). Fares point at them; ids mean nothing outside this reply. |
| `results[]` | array | always | must | One group per set of journeys the fares cover. Pick one option and one fare from each group until every journey of your request is covered. |
| `results[].journey_indexes` | array of integer | always | must | Which journeys of your request this group's fares cover: [0] onward only, [1] return only, [0, 1] a combined fare for both. |
| `results[].options[].option_id` | string | always | must | Names the flights of this option. Send it to reprice with the price_id of the chosen fare. |
| `results[].options[].segments[]` | array | always | must | The flights of this option in order, each named by (journey_index, segment_index); segment_index restarts at 0 in every journey. |
| `results[].options[].segments[].operating_airline_code` | string | only on a codeshare | useful | The airline that flies the aircraft when it differs from airline_code, the airline selling the seat. Show it to the traveller. |
| `results[].options[].fare_options[]` | array | always | must | The fares sold on exactly these flights. Each prices the whole option once; no amount appears anywhere else. |
| `results[].options[].fare_options[].price_id` | string | always | must | Names this fare. Send it to reprice with the option_id. |
| `results[].options[].fare_options[].adult` | object | always | must | What this fare gives an adult: fare (the price for the whole option), fare_ref, refundable_type, cabin_class, booking_class, fare_basis, baggage. child and infant appear only when requested. |
| `results[].options[].fare_options[].adult.fare.total_fare` | number | always | must | What the traveller pays for one adult on this option, taxes included. |
| `results[].options[].fare_options[].adult.fare.net_fare` | number | always | must | What you pay us for one adult: total_fare less your commission. |
| `results[].options[].fare_options[].adult.baggage` | object | when the airline states it | useful | Allowance included in the fare: hand and checkin, each {kg} and/or {pieces}. Absent = not stated. |
| `results[].options[].fare_options[].fare_rules` | object | when a rule is known at search | useful | Journey index → id in the top-level fare_rules. A missing index has no rule known at search; the reprice reply carries the final rules. |
| `results[].options[].fare_options[].varies_by_segment` | boolean | always | info | true when a later flight of this fare differs from the first in cabin, meal, booking class, fare basis or baggage. Ask detail=segment to see them per flight. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) | Missing, expired or foreign token; also when the API cannot be reached. |
| 400 | 5100 | Invalid search request (cabin_class must be 1 (economy), 2 (premium), 3 (business), or 4 (first)) | errors[] has field cabin_class, rule one_of. Same for fare_types and the engine's own checks (dates, airport codes, pax counts). |
| 500 | 9000 | Something went wrong |  |

Questions developers ask:

- **What do I send to reprice for a domestic return?** Two items: one option and one fare from group [0] (onward) and one from group [1] (return). An international return has one group [0, 1] and one item.
- **Why does commission not appear on my fares?** Zero amounts are left out. commission appears only when a commission rule applies to your account; net_fare is then total_fare less it.
- **How long can I use an option_id and price_id?** Until valid_till of the search reply. After it, search again.
- **What does varies_by_segment true mean?** A later flight of the fare differs from the first in cabin, meal, booking class, fare basis or baggage. Send detail=segment to see every flight.

### 3. `POST /flights/reprice`

Reprice the chosen fare(s) with the airline and return the itinerary: the final price, what the booking needs (passport, DOB, GST, hold allowed) and any price change.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "items": [
    {
      "option_id": "3f9e8d7c-6b5a-4f3e-9d2c-1b0a9f8e7d6c",
      "price_id": "7c1b2f3e-9a4d-4c2e-8f1a-2b3c4d5e6f70"
    }
  ]
}
```

- items: one entry per fare; a return sold as two one-way fares sends two items. option_id and price_id at top level are accepted for a single fare.

Reply:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "valid_till": "2026-10-18T20:27:00+05:30",
  "fare_rules": {
    "fr_1": {
      "cancellation": [
        {
          "allowed": false,
          "from": {
            "value": 0,
            "unit": "HOURS"
          },
          "to": {
            "value": 3,
            "unit": "HOURS"
          },
          "text": "Non-refundable within 3 hours of departure"
        },
        {
          "allowed": true,
          "amount": 3899,
          "from": {
            "value": 3,
            "unit": "HOURS"
          },
          "to": {
            "value": 365,
            "unit": "DAYS"
          }
        }
      ],
      "date_change": [
        {
          "allowed": true,
          "amount": 2999,
          "from": {
            "value": 3,
            "unit": "HOURS"
          },
          "to": {
            "value": 365,
            "unit": "DAYS"
          }
        }
      ]
    }
  },
  "results": [
    {
      "journey_indexes": [
        0
      ],
      "option_id": "3f9e8d7c-6b5a-4f3e-9d2c-1b0a9f8e7d6c",
      "segments": [
        {
          "segment_index": 0,
          "journey_index": 0,
          "segment_id": "BLR_BOM_QP_1101",
          "from": "BLR",
          "to": "BOM",
          "airline_code": "QP",
          "airline_name": "Akasa Air",
          "aircraft_type": "737 MAX 8",
          "flight_number": "1101",
          "departure_time": "2026-11-14T06:00:00",
          "departure_terminal": "1",
          "arrival_time": "2026-11-14T07:45:00",
          "arrival_terminal": "2",
          "duration": 105
        }
      ],
      "fare": {
        "price_id": "7c1b2f3e-9a4d-4c2e-8f1a-2b3c4d5e6f70",
        "fare_rules": {
          "0": "fr_1"
        },
        "adult": {
          "fare_ref": "SAVER",
          "refundable_type": "PARTIALLY_REFUNDABLE",
          "cabin_class": "Economy",
          "booking_class": "Q",
          "fare_basis": "QPSAVER",
          "baggage": {
            "hand": {
              "kg": 7
            },
            "checkin": {
              "kg": 15
            }
          },
          "fare": {
            "hand_baggage": "7Kg",
            "checkin_baggage": "15Kg",
            "base_fare": 4200.0,
            "yq": 0.0,
            "yr": 0.0,
            "airline_gst": 0.0,
            "booking_fee": 0.0,
            "commission": 0.0,
            "other_taxes": 812.0,
            "total_fare": 5012.0,
            "net_fare": 5012.0,
            "pax_count": 1
          }
        },
        "varies_by_segment": false
      }
    }
  ],
  "booking_requirements": {
    "is_gst_mandatory": false,
    "pan_applicable": false,
    "passport_mandatory": false,
    "dob_applicable": {
      "adt": false,
      "chd": true,
      "inf": true
    },
    "is_hold": true,
    "firstname_length": 30,
    "lastname_length": 30,
    "firstname_min_length": 2,
    "lastname_min_length": 2,
    "seat_mandatory": false,
    "meal_mandatory": false,
    "baggage_mandatory": false
  },
  "price": {
    "adult": {
      "hand_baggage": "7Kg",
      "checkin_baggage": "15Kg",
      "base_fare": 4200.0,
      "yq": 0.0,
      "yr": 0.0,
      "airline_gst": 0.0,
      "booking_fee": 0.0,
      "commission": 0.0,
      "other_taxes": 812.0,
      "total_fare": 5012.0,
      "net_fare": 5012.0,
      "pax_count": 1
    },
    "total": {
      "hand_baggage": "7Kg",
      "checkin_baggage": "15Kg",
      "base_fare": 4200.0,
      "yq": 0.0,
      "yr": 0.0,
      "airline_gst": 0.0,
      "booking_fee": 0.0,
      "commission": 0.0,
      "other_taxes": 812.0,
      "total_fare": 5012.0,
      "net_fare": 5012.0,
      "pax_count": 1
    }
  },
  "messages": [
    {
      "type": "FARE_ALERT",
      "option_id": "3f9e8d7c-6b5a-4f3e-9d2c-1b0a9f8e7d6c",
      "message": "Fare has changed: previous price 5012.00, current price 5112.00 (difference: 100.00)",
      "old_value": 5012.0,
      "new_value": 5112.0
    }
  ]
}
```

- booking_requirements.is_hold says whether POST /flights/book may be called with is_hold true; the other fields say what the booking must carry (GST, PAN, passport, dates of birth, name lengths, mandatory seat, meal or bag).
- results[] has one entry per item sent: the option's flights and the one fare, priced again, in the fare shape of search (detail=segment adds segments[] inside fare). fare_rules holds the rules those fares point at.
- valid_till is when the supplier's session for this itinerary ends (the API's review session, default 15 minutes); book before it.
- messages is absent when nothing changed; otherwise one entry per repriced option with type FARE_ALERT, the option_id, and the old and new value.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `items[]` | array | required, one per group | must | One item per search group you chose from: one for a one way or a combined return, two for a domestic return (one per direction). |
| `items[].option_id` | string | required | must | The option_id from the search reply. |
| `items[].price_id` | string | required | must | The price_id of the chosen fare of that option. An option_id or price_id not in a current search answers 400 with errors[] (search again). |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `itinerary_id` | string | always | must | Names the repriced itinerary. Send it to ancillaries, seat map and book. |
| `valid_till` | datetime | always | must | Until when the itinerary_id can be booked. After it, book answers 410: reprice again. |
| `results[]` | array | always | must | One entry per item sent: journey_indexes, option_id, the flights (segments) and the one fare, priced again. |
| `results[].segments[]` | array | always | must | The flights in order, each named by (journey_index, segment_index); segment_index restarts at 0 in every journey. |
| `results[].fare` | object | always | must | The fare in the shape of search: price_id, per passenger type (adult, child, infant) the fare_ref, refundable_type, cabin_class, booking_class, fare_basis, baggage and fare, and fare_rules ids. |
| `price.total` | object | always | must | The price in the components of search: base_fare, yq, yr, airline_gst, booking_fee, commission, other_taxes, total_fare (what the traveller pays), net_fare (what you pay us), pax_count, and the baggage stated in the fare. For the whole booking. |
| `price.adult (child, infant)` | object | always (child, infant when requested) | useful | The price in the components of search: base_fare, yq, yr, airline_gst, booking_fee, commission, other_taxes, total_fare (what the traveller pays), net_fare (what you pay us), pax_count, and the baggage stated in the fare. For one passenger of that type. |
| `booking_requirements` | object | always | must | What book must carry: is_gst_mandatory, pan_applicable, passport_mandatory, dob_applicable (adt, chd, inf), name lengths, and whether a seat, meal or bag is mandatory. |
| `booking_requirements.is_hold` | boolean | always | must | true when this fare may be booked on hold (book with is_hold true); false: book directly, paid at once. |
| `fare_rules` | object | when known | useful | The cancellation and date-change rules the fares point at, keyed by id (fr_1, …): bands with allowed, amount or percent, the window (from, to) and the airline's text. |
| `messages[]` | array | only when the price changed | must | One entry per repriced option whose price changed since search: type FARE_ALERT, option_id, old_value, new_value. Show the new price before booking. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 400 | 5100 | Invalid search request (option_id and price_id are required) | Also 'each review item needs option_id and price_id'. |
| 404 | 5103 | Flight not found | option_id or price_id not in a stored search. |
| 410 | 5102 | Search results have expired |  |
| 502 | 5001 | The airline or supplier could not complete the request | Reprice failed at the airline. |
| 504 | 5002 | A supplier or service did not answer in time |  |

Questions developers ask:

- **The price changed. What now?** messages has a FARE_ALERT with old_value and new_value for that option_id. Show the new price to the traveller before booking; the itinerary is priced at the new value.
- **Until when can I book?** valid_till of the reprice reply: the airline's session for this itinerary. Book before it or reprice again.

### 4. `POST /flights/ancillaries`

Optional. Baggage, meal and other add-ons on sale on the itinerary, each with the journey and the flights it covers.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e"
}
```


Reply:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "segments": [
    {
      "journey_index": 0,
      "segment_index": 0,
      "airline_code": "QP",
      "flight_number": "1101",
      "from": "BLR",
      "to": "BOM"
    }
  ],
  "baggage": [
    {
      "journey_index": 0,
      "items": [
        {
          "code": "XBAG05",
          "label": "Extra 5 Kg",
          "price": 1500.0
        }
      ]
    }
  ],
  "meal": [
    {
      "journey_index": 0,
      "segment_index": 0,
      "items": [
        {
          "code": "VGML",
          "label": "Vegetarian meal",
          "price": 350.0
        }
      ]
    }
  ],
  "other": []
}
```

- segments[] repeats the itinerary's flights, each named by (journey_index, segment_index) as in search and reprice; segment_index restarts at 0 inside every journey.
- Bags are sold per journey: baggage[] has one entry per journey. Meals and other items are sold per flight: meal[] and other[] have one entry per flight. A journey or flight absent from a bucket offers nothing of that type.
- On book, send a bag with its code and journey_index; a meal, other item or seat with its code, journey_index and segment_index.
- errors[] (plain strings) appears when one flight's catalogue failed; the rest is still returned.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `itinerary_id` | string | required | must | The itinerary_id from reprice. An expired one answers 404: reprice again. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `segments[]` | array | always | useful | The flights of the itinerary, each named by (journey_index, segment_index), with airline_code, flight_number, from and to. |
| `baggage[]` | array | always (empty when none) | must | Extra bags per journey: journey_index and items. A bag covers every flight of its journey, so it has no segment_index. |
| `meal[]` | array | always (empty when none) | must | Meals per flight: journey_index, segment_index and items. |
| `other[]` | array | always (empty when none) | useful | Other items per flight (priority check-in, bundles): journey_index, segment_index and items. |
| `<list>[].items[]` | array | always | must | What can be bought: code (send it to book), label (show it), price (per passenger, INR). |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 400 | 5100 | Invalid search request (itinerary_id is required) | errors[]: field itinerary_id, rule required. |
| 404 | 5104 | Itinerary not found or expired | Unknown or expired itinerary_id. |
| 502 | 5001 | The airline or supplier could not complete the request |  |

Questions developers ask:

- **How do I send a bag and a meal on book?** A bag with its code and journey_index; a meal, seat or other item with its code, journey_index and segment_index, exactly as this reply gave them.

### 5. `POST /flights/seat-map`

Optional. The seat map of every flight of the itinerary with price and availability per seat.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e"
}
```


Reply:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "segments": [
    {
      "journey_index": 0,
      "segment_index": 0,
      "airline_code": "QP",
      "flight_number": "1101",
      "from": "BLR",
      "to": "BOM"
    }
  ],
  "seats": [
    {
      "journey_index": 0,
      "segment_index": 0,
      "aircraft_type": "737 MAX 8",
      "total_seats": 189,
      "seats": [
        {
          "aisle": false,
          "amount": 600.0,
          "code": "WINDOW",
          "column": 1,
          "desc": "1A",
          "exit_row": false,
          "infant": true,
          "is_available": true,
          "leg_room": true,
          "middle": false,
          "near_wings": false,
          "reclining": true,
          "row": 1,
          "tax": 0.0,
          "window": true
        }
      ]
    }
  ]
}
```

- segments[] as in ancillaries; each seats block names its flight by (journey_index, segment_index). desc is the seat label (1A) that goes into the booking; code is the seat type.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `itinerary_id` | string | required | must | The itinerary_id from reprice. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `segments[]` | array | always | useful | The flights of the itinerary, each named by (journey_index, segment_index), with airline_code, flight_number, from and to. |
| `seats[]` | array | always (empty when the airline gives no map) | must | One seat map per flight: journey_index, segment_index, aircraft_type, total_seats and seats. |
| `seats[].seats[]` | array | always | must | Every seat: code (send it to book), desc (e.g. 3A, show it), row, column, amount (price; 0 = free), tax, is_available. |
| `seats[].seats[].window / aisle / middle` | boolean | always | useful | Where the seat is in its row. |
| `seats[].seats[].exit_row / leg_room / infant / near_wings / reclining` | boolean | always | useful | Seat features. A passenger with an infant needs a seat with infant true; exit rows have rules of their own. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 400 | 5100 | Invalid search request (itinerary_id is required) |  |
| 404 | 5104 | Itinerary not found or expired |  |
| 502 | 5001 | The airline or supplier could not complete the request |  |

### 6. `POST /flights/book`

Save the passengers on the itinerary, then pay from the wallet and ticket (is_hold false) or hold the booking without payment (is_hold true).

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "is_hold": false,
  "gst_details": {
    "name": "Example Travels Pvt Ltd",
    "number": "27AABCE1234F1Z5",
    "address": "12 MG Road, Mumbai 400001",
    "email": "accounts@example.com",
    "mobile": "+919876543210"
  },
  "pax_details": [
    {
      "first_name": "Rahul",
      "last_name": "Sharma",
      "pax_type": "ADULT",
      "title": "Mr",
      "gender": "male",
      "dob": "1990-05-12",
      "phone": "+919876543210",
      "email": "rahul.sharma@example.com",
      "passport_details": {
        "passport_number": "Z1234567",
        "passport_issue_date": "2022-01-10",
        "passport_expiry_date": "2032-01-09",
        "passport_issue_country": "IN",
        "nationality": "IN"
      },
      "ancillaries": {
        "seat": [
          {
            "code": "1A",
            "price": 600.0,
            "label": "window",
            "journey_index": 0,
            "segment_index": 0
          }
        ],
        "baggage": [
          {
            "code": "XBAG05",
            "price": 1500.0,
            "label": "Extra 5 Kg",
            "journey_index": 0
          }
        ],
        "meal": [],
        "other": []
      }
    }
  ]
}
```

- pax_details: one per traveller, at least one. pax_type ADULT, CHILD or INFANT; title Mr, Mrs, Ms, Mstr, Miss; gender male or female; dates YYYY-MM-DD (values as the web frontend sends them; the validator names are passenger_type, passenger_title, gender, dateformat).
- phone and email are required on every passenger; the first passenger's pair is stored as the customer contact.
- gst_details is optional as a block; when present, all five fields are required and number must be a valid GSTIN.
- passport_details is optional; send it when review's requirements say passport_applicable.

Reply:

```json
{
  "booking_id": "AIOR482913",
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "status": "SUCCESS",
  "amount": 7112.0
}
```

Hold (is_hold true):

```json
{
  "booking_id": "AIOR482914",
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "status": "ONHOLD",
  "amount": 7112.0,
  "pay_till": "2026-10-17T10:12:00Z"
}
```

- status is the payment status for a paid booking (SUCCESS; PENDING when the ticket is not yet issued) and ONHOLD for a hold.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `itinerary_id` | string | required | must | The itinerary_id from reprice, before its valid_till. |
| `is_hold` | boolean | optional, default false | must | false: book directly, paid at once from your balance or credit and ticketed. true: hold the seats without payment until pay_till (only when reprice said booking_requirements.is_hold true); then confirm-hold or release. |
| `pax_details[]` | array | required, one per passenger | must | Every passenger of the search, adults first: first_name, last_name, pax_type (ADULT, CHILD, INFANT), title, gender, dob, phone and email. |
| `pax_details[].passport_details` | object | when reprice says passport_mandatory | useful | passport_number, passport_issue_date, passport_expiry_date, passport_issue_country, nationality. |
| `pax_details[].ancillaries` | object | optional | useful | What this passenger buys: seat[], meal[], other[] (each with code, price, label, journey_index and segment_index) and baggage[] (code, price, label, journey_index; no segment_index). Codes come from ancillaries and seat map; an item on a flight not in the itinerary answers 400 with errors[] (rule scope). |
| `gst_details` | object | optional; required when reprice says is_gst_mandatory | useful | The company on the invoice: name, number (GSTIN), address, email, mobile. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `booking_id` | string | always | must | Your booking's id. Send it to booking details, confirm-hold and release. |
| `status` | string | always | must | ONHOLD (held, pay before pay_till), SUCCESS (booked directly and paid), PENDING (the airline has not confirmed yet: read the booking details), or the booking's state. |
| `pay_till` | datetime | on a hold | must | Until when the hold can be confirmed; after it the airline releases the seats. |
| `amount` | number | always | must | What the booking costs (INR); taken at once for a direct booking, at confirm-hold for a hold. |
| `itinerary_id` | string | always | info | The itinerary that was booked. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 403 | 9002 | You do not have permission for this action | Role without bookings.create (Finance, Operation, Tech). |
| 400 | 3000 | Invalid request ((the API's detail text)) |  |
| 400 | 9003 | Some fields are missing or invalid | Schema validation of the body (required fields, formats); errors[] lists them. |
| 503 | 3003 | A service the API depends on is unavailable ((the API's text)) | the API answered 5xx or did not answer. |
| 409 | 3101 | Hold booking limit reached |  |
| 500 | 9000 | Something went wrong | Payment or order errors that no translator knows. |

Questions developers ask:

- **Is gst_details required?** Only when booking_requirements.is_gst_mandatory is true. When you send it, all five fields are required.
- **What is the difference between is_hold true and false?** false pays from your wallet and tickets at once. true holds the seats without payment until pay_till; confirm with confirm-hold or give them back with release.

### 7. `POST /flights/booking/details`

The booking as stored: status, payment status, the flights with the PNR, the passengers with their fare and ticket number per flight, the price.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "booking_id": "AIOR482913"
}
```


Reply:

```json
{
  "booking_id": "AIOR482913",
  "status": "SUCCESS",
  "payment_status": "SUCCESS",
  "created_at": "2026-10-15T10:12:34Z",
  "route_type": "DOMESTIC",
  "journeys": [
    {
      "journey_index": 0,
      "from": "BLR",
      "to": "BOM",
      "departure_time": "2026-11-14T06:00:00",
      "arrival_time": "2026-11-14T07:45:00",
      "segments": [
        {
          "segment_index": 0,
          "from": "BLR",
          "to": "BOM",
          "airline_code": "QP",
          "airline_name": "Akasa Air",
          "flight_number": "1101",
          "departure_time": "2026-11-14T06:00:00",
          "arrival_time": "2026-11-14T07:45:00",
          "departure_terminal": "1",
          "arrival_terminal": "2",
          "duration": 105
        }
      ],
      "passengers": [
        {
          "passenger_index": 0,
          "first_name": "Rahul",
          "last_name": "Sharma",
          "pax_type": "ADULT",
          "title": "Mr",
          "gender": "male",
          "dob": "1990-05-12",
          "passport_details": {
            "passport_number": "Z1234567",
            "passport_issue_date": "2022-01-10",
            "passport_expiry_date": "2032-01-09",
            "nationality": "IN"
          },
          "fare": {
            "base_fare": 4200.0,
            "yq": 500.0,
            "other_taxes": 312.0,
            "ancillaries": 2100.0,
            "total_fare": 7112.0,
            "net_fare": 7112.0
          },
          "status": "CONFIRMED",
          "pnr": "H7K2PQ",
          "ticket_number": "",
          "fare_ref": "SAVER",
          "refundable_type": "PARTIALLY_REFUNDABLE",
          "cabin_class": "Economy",
          "booking_class": "Q",
          "fare_basis": "QPSAVER",
          "baggage": {
            "hand": {
              "kg": 7
            },
            "checkin": {
              "kg": 15
            }
          },
          "ancillaries": {
            "seat": [
              {
                "code": "1A",
                "price": 600.0,
                "label": "window",
                "segment_index": 0
              }
            ],
            "baggage": [
              {
                "code": "XBAG05",
                "price": 1500.0,
                "label": "Extra 5 Kg"
              }
            ]
          }
        }
      ]
    }
  ],
  "price": {
    "base_fare": 4200.0,
    "yq": 500.0,
    "other_taxes": 312.0,
    "ancillaries": 2100.0,
    "total_fare": 7112.0,
    "net_fare": 7112.0
  },
  "gst_details": {
    "name": "Example Travels Pvt Ltd",
    "number": "27AABCE1234F1Z5",
    "address": "12 MG Road, Mumbai 400001",
    "email": "accounts@example.com",
    "mobile": "+919876543210"
  }
}
```

- journeys[] is the booking journey by journey: its dates, its flights (segment_index restarts at 0 inside each journey; operating airline shown only on a codeshare) and, for every passenger on it, who they are (passenger_index is the same person on every journey), the status, the PNR, the ticket number, the fare paid for that journey in the components of the search price plus ancillaries, the fare attributes (fare_ref, refundable_type, cabin, booking class, fare basis, included baggage) and the ancillaries bought (a seat or meal with its segment_index, a bag without).
- status per passenger per journey is PENDING until the booking is held or ticketed, then CONFIRMED; CANCELLED, VOIDED or REISSUED come later. price is the booking as a whole in the same components, total_fare and net_fare included.
- pay_till appears on a held booking. Zero fare fields are omitted (omitempty).
- status values are the API's order statuses: CREATED, PENDING, SUCCESS, ONHOLD, FAILED, PNR_RELEASED, CANCELLED, ABORTED.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `booking_id` | string | required | must | The id book returned. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `status` | string | always | must | The booking's state: CREATED, ONHOLD, SUCCESS, PNR_RELEASED, CANCELLED, FAILED. |
| `payment_status` | string | always | must | PENDING until paid, then SUCCESS; FAILED or REFUNDED later. |
| `pay_till` | datetime | on a hold | must | Until when a held booking can be confirmed; after it the airline releases the seats. |
| `journeys[]` | array | always | must | The booking journey by journey: its dates, its flights and, for every passenger on it, who they are, their state, the PNR, the ticket, the fare paid for that journey and the add-ons. |
| `journeys[].passengers[].pnr` | string | once the airline confirmed | must | The airline's record locator for this passenger on this journey. Empty until the hold or the ticket is confirmed. |
| `journeys[].passengers[].status` | string | always | must | PENDING until confirmed, then CONFIRMED; CANCELLED, VOIDED or REISSUED when something happened to this passenger on this journey. |
| `price` | object | always | must | The booking's price as a whole, in the components of the search price (base_fare, yq, yr, airline_gst, booking_fee, commission, other_taxes, total_fare, net_fare) plus ancillaries and fees. |
| `journeys[].passengers[].fare` | object | always | must | What this passenger's journey cost, in the components of the search price plus ancillaries bought on it. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 403 | 9002 | You do not have permission for this action | Role without bookings.read. |
| 400 | 3000 | Invalid request (Booking_id is required) |  |
| 404 | 9005 | Not found (Booking not found) |  |

Questions developers ask:

- **Why is pnr empty?** The airline has not confirmed yet: the passenger reads PENDING. It appears once the hold or the ticket is confirmed.

### 8. `POST /flights/booking/confirm-hold`

Pay a held booking from the wallet and ticket it, before pay_till.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "booking_id": "AIOR482914"
}
```


Reply:

```json
{
  "booking_id": "AIOR482914",
  "itinerary_id": "9b8a7f6e-5d4c-4b3a-2f1e-0d9c8b7a6f5e",
  "status": "SUCCESS",
  "amount": 7112.0
}
```


Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `booking_id` | string | required | must | A booking on hold (status ONHOLD), before its pay_till. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `status` | string | always | must | SUCCESS when paid and ticketed; read the booking details for the tickets. |
| `amount` | number | always | must | What was taken from your balance or credit (INR). |
| `booking_id` | string | always | info | The booking confirmed. |
| `itinerary_id` | string | always | info | Its itinerary. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 403 | 9002 | You do not have permission for this action | Role without bookings.hold. |
| 400 | 3000 | Invalid request (Booking_id is required) |  |
| 404 | 9005 | Not found (Booking not found) |  |
| 409 | 3102 | Booking is not pending | Not a held booking, or already confirmed. |
| 500 | 9000 | Something went wrong | Insufficient wallet or payment faults that no translator knows. |

### 9. `POST /flights/booking/release`

Give up a held booking: the PNR is released at the airline and the order becomes PNR_RELEASED. A ticketed booking cannot be released.

Auth: Authorization: Bearer <token> from generate-token.

Request:

```json
{
  "booking_id": "AIOR482914"
}
```


Reply:

```json
{
  "booking_id": "AIOR482914",
  "status": "PNR_RELEASED",
  "pnr": "H7K2PQ"
}
```

- success is false when every provider release failed; status then stays as it was.

Request keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `booking_id` | string | required | must | A booking on hold. A booking that is not on hold answers an error. |

Reply keys:

| key | type | when present | importance | meaning |
|---|---|---|---|---|
| `status` | string | always | must | PNR_RELEASED when the airline freed the seats. A release the airline refuses answers 409 (code 3105): the PNR is still held, try again later. |
| `pnr` | string | always | useful | The record locator that was released. |
| `booking_id` | string | always | info | The booking released. |

Errors:

| HTTP | code | message | when |
|---|---|---|---|
| 401 | 9001 | Authentication required (Invalid token) |  |
| 403 | 9002 | You do not have permission for this action | Role without bookings.cancel. |
| 400 | 3000 | Invalid request (Booking_id is required) |  |
| 404 | 9005 | Not found (Booking not found) |  |
| 409 | 3102 | Booking is not pending | Ticketed or already released. |

Questions developers ask:

- **Release answered 409 3105. Is the booking released?** No. The airline did not give the PNR back; it stays held until pay_till. Try again later.

## Error codes

### Common to every call

| code | message | when |
|---|---|---|
| 9000 | 500 | Something went wrong An unexpected fault; the cause is logged under traceId. |
| 9001 | 401 | Authentication required No valid token or API key, or the token expired. |
| 9002 | 403 | You do not have permission for this action |
| 9003 | 400 | Some fields are missing or invalid Schema validation; errors[] lists field, rule, params. |
| 9004 | 429 | Too many requests Rate limit. |
| 9005 | 404 | Not found The record does not exist or is not the caller's. |
| 9006 | 499 | Request cancelled The caller closed the request before the answer. |

### Search, reprice, ancillaries, seat map

| code | message | when |
|---|---|---|
| 5000 | 400 | Invalid request |
| 5001 | 502 | The airline or supplier could not complete the request Supplier or the API error. |
| 5002 | 504 | A supplier or service did not answer in time Timeout. No raise site in the code. |
| 5003 | 503 | A service the API depends on is unavailable |
| 5004 | 502 | The payment could not be completed Not public. No raise site in the code. |
| 5100 | 400 | Invalid search request Search, review or itinerary request invalid. Raised by all four external the API routes. |
| 5101 | 404 | Search not found No raise site in the code. |
| 5102 | 410 | Search results have expired No raise site in the code. |
| 5103 | 404 | Flight not found Raised by review (and the UI's search details routes). |
| 5104 | 404 | Itinerary not found or expired Add-ons and seat map on an unknown itinerary. |
| 5105 | 400 | The supplier does not support this route or cabin No raise site in the code. |
| 5106 | 404 | Supplier account not found Not public. No raise site in the code. |
| 5200 | 404 | Booking not found No raise site in the code; the API's internal book routes answer 9000 instead. |

### Book, details, hold

| code | message | when |
|---|---|---|
| 3000 | 400 | Invalid request |
| 3001 | 400 | A required field is missing Declared on the internal create routes; never raised. |
| 3002 | 400 | A field has an invalid value Declared on the internal create routes; never raised. |
| 3003 | 503 | A service the API depends on is unavailable |
| 3100 | 404 | Booking not found Internal routes. The external routes answer the generic 9005 instead. |
| 3101 | 409 | Hold booking limit reached Hold path. |
| 3102 | 409 | Booking is not pending Confirm or release on a booking in the wrong state. |
| 3103 | 409 | Booking is not assigned Ops routes only. |
| 3104 | 409 | Booking fare does not match the airline PNR Import route only. |

## Test cases

Captured on our test environment. Each step's request and reply are in the collection's "Test cases" folder and on the site.

### Domestic, one way, 1 adult

Domestic one way for 1 adult: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. One search segment; one group, journey_indexes [0]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 262 options
  - 262 options in 1 group(s): journey_indexes [0] has 262 options
  - Options by number of flights: 1 flight: 83, 2 flights: 179
  - Airlines in the reply: 6E (156 flights), AI (89 flights), IX (67 flights), H1 (38 flights), SG (28 flights), EK (20 flights), SQ (18 flights), EY (16 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1021 fare options in total; 47 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option eff1ddbb… / price 520060e3…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 21 items
  - 1 flight(s) in segments[]: (journey 0, segment 0) IX 1038 DEL-NMI
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 11 meals (per flight): (journey 0, segment 0): 11 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 168 seats
  - 1 flight(s) with a seat map of 1 in the itinerary: (journey 0, segment 0) Boeing 7M8, 168 seats
  - 168 seats available of 168; free: 10; paid: 158 (from 300 to 1,700)
  - Window 53, aisle 56, middle 59; exit row 0; extra leg room 0; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR799682, amount 3,002, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR LVE69F, ticket BX21HJ00021-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Chawla
- **Release the hold** `POST /flights/booking/release`: HTTP 409
  - Failed with HTTP 409: The hold could not be released; the PNR is still held
  - This reply is the sample: later steps of the case were not called with it.

### Domestic, one way, 1 adult, 1 child, 1 infant

Domestic one way for 1 adult, 1 child, 1 infant: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. One search segment; one group, journey_indexes [0]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 166 options
  - 166 options in 1 group(s): journey_indexes [0] has 166 options
  - Options by number of flights: 1 flight: 43, 2 flights: 123
  - Airlines in the reply: AI (95 flights), IX (67 flights), H1 (36 flights), SG (28 flights), EK (20 flights), SQ (18 flights), EY (16 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 692 fare options in total; 37 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 16560204… / price d2f877b1…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price changed since search for option 16560204…: FARE_ALERT 6,004 → 9,004
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 21 items
  - 1 flight(s) in segments[]: (journey 0, segment 0) IX 1038 DEL-NMI
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 11 meals (per flight): (journey 0, segment 0): 11 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 168 seats
  - 1 flight(s) with a seat map of 1 in the itinerary: (journey 0, segment 0) Boeing 7M8, 168 seats
  - 156 seats available of 168; free: 10; paid: 146 (from 300 to 1,700)
  - Window 49, aisle 52, middle 55; exit row 0; extra leg room 0; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 3 passengers
  - Booked on hold (is_hold True) with 3 passenger(s): ADULT 1, CHILD 1, INFANT 1
  - Status ONHOLD, booking_id AIOR693516, amount 9,004, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 3 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR O3QCYJ, ticket BX21HJ00031-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  -   passenger 1 CHILD Anya: CONFIRMED, PNR O3QCYJ, ticket BX21HJ00031-2, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
- **Release the hold** `POST /flights/booking/release`: HTTP 409
  - Failed with HTTP 409: The hold could not be released; the PNR is still held
  - This reply is the sample: later steps of the case were not called with it.

### Domestic, return, 1 adult

Domestic return for 1 adult: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. Two search segments. Domestic fares are sold per direction: two groups, [0] and [1]; reprice takes two items.

- **Search** `POST /flights/search`: HTTP 200, 337 options
  - 337 options in 2 group(s): journey_indexes [0] has 166 options; journey_indexes [1] has 171 options
  - Options by number of flights: 1 flight: 78, 2 flights: 259
  - Airlines in the reply: AI (214 flights), IX (145 flights), SG (60 flights), H1 (59 flights), EK (42 flights), SQ (34 flights), EY (32 flights), QP (6 flights), WY (2 flights), 6E (1 flights), 9I (1 flights)
  - 1631 fare options in total; 42 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 2 items
  - 2 item(s) sent: option 33f7112a… / price 39baf0d4…; option 7ee707d5… / price f2973366…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1463 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Repriced option on journey_indexes [1]: 2 flights (IX 1163 BOM-GOX, IX 2764 GOX-DEL); multi-flight reprice: yes
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 82 items
  - 3 flight(s) in segments[]: (journey 0, segment 0) IX 1463 DEL-NMI; (journey 1, segment 0) IX 1163 BOM-GOX; (journey 1, segment 1) IX 2764 GOX-DEL
  - 20 bags (per journey): journey 0: 10 items; journey 1: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 37 meals (per flight): (journey 0, segment 0): 11 items; (journey 1, segment 0): 10 items; (journey 1, segment 1): 16 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 602 seats
  - 3 flight(s) with a seat map of 3 in the itinerary: (journey 0, segment 0) Airbus A32Y, 232 seats; (journey 1, segment 0) 7M8, 184 seats; (journey 1, segment 1) 32N, 186 seats
  - 602 seats available of 602; free: 16; paid: 586 (from 300 to 1,700)
  - Window 195, aisle 202, middle 202; exit row 22; extra leg room 36; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR432493, amount 5,743, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1463 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR SYJBUE, ticket BX21HJ00071-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  - Journey 1 BOM-DEL: segment 0 IX 1163 BOM-GOX; segment 1 IX 2764 GOX-DEL
- **Release the hold** `POST /flights/booking/release`: HTTP 200, 1 released
  - Status after release: PNR_RELEASED

### Domestic, return, 1 adult, 1 child, 1 infant

Domestic return for 1 adult, 1 child, 1 infant: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. Two search segments. Domestic fares are sold per direction: two groups, [0] and [1]; reprice takes two items.

- **Search** `POST /flights/search`: HTTP 200, 333 options
  - 333 options in 2 group(s): journey_indexes [0] has 165 options; journey_indexes [1] has 168 options
  - Options by number of flights: 1 flight: 77, 2 flights: 256
  - Airlines in the reply: AI (212 flights), IX (145 flights), SG (60 flights), H1 (55 flights), EK (42 flights), SQ (34 flights), EY (32 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1187 fare options in total; 36 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 2 items
  - 2 item(s) sent: option 348035e5… / price 70060236…; option a17d077f… / price d519d70c…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Repriced option on journey_indexes [1]: 1 flight (IX 8006 BOM-DEL); multi-flight reprice: no
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 42 items
  - 2 flight(s) in segments[]: (journey 0, segment 0) IX 1038 DEL-NMI; (journey 1, segment 0) IX 8006 BOM-DEL
  - 20 bags (per journey): journey 0: 10 items; journey 1: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 22 meals (per flight): (journey 0, segment 0): 11 items; (journey 1, segment 0): 11 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 354 seats
  - 2 flight(s) with a seat map of 2 in the itinerary: (journey 0, segment 0) Boeing 7M8, 168 seats; (journey 1, segment 0) Airbus A32N, 186 seats
  - 327 seats available of 354; free: 24; paid: 303 (from 300 to 1,700)
  - Window 107, aisle 107, middle 113; exit row 0; extra leg room 0; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 3 passengers
  - Booked on hold (is_hold True) with 3 passenger(s): ADULT 1, CHILD 1, INFANT 1
  - Status ONHOLD, booking_id AIOR196466, amount 17,278, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 3 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR U68PXD, ticket BX21HJ00051-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  -   passenger 1 CHILD Anya: CONFIRMED, PNR U68PXD, ticket BX21HJ00051-2, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
- **Release the hold** `POST /flights/booking/release`: HTTP 409
  - Failed with HTTP 409: The hold could not be released; the PNR is still held
  - This reply is the sample: later steps of the case were not called with it.

### International, one way, 1 adult

International one way for 1 adult: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. One search segment; one group, journey_indexes [0]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 194 options
  - 194 options in 1 group(s): journey_indexes [0] has 194 options
  - Options by number of flights: 1 flight: 15, 2 flights: 173, 3 flights: 6
  - Airlines in the reply: AI (68 flights), QR (66 flights), IX (30 flights), EK (28 flights), H1 (26 flights), GF (20 flights), EY (16 flights), WY (16 flights), SV (14 flights), BA (14 flights), SG (12 flights), UL (11 flights), TK (10 flights), ET (8 flights), XY (8 flights), MS (6 flights), LH (5 flights), SQ (4 flights), KU (4 flights), FZ (3 flights), AZ (2 flights), J2 (2 flights), LX (2 flights), CX (2 flights), HY (1 flights), LO (1 flights)
  - 1065 fare options in total; 108 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option edecb614… / price ae7740f4…
  - Repriced option on journey_indexes [0]: 2 flights (QR 4771 DEL-DOH, QR 1022 DOH-DXB); multi-flight reprice: yes
  - Fare Economy Classic PARTIALLY_REFUNDABLE: adult total 19,714, net 19,714; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 0 items
  - 2 flight(s) in segments[]: (journey 0, segment 0) QR 4771 DEL-DOH; (journey 0, segment 1) QR 1022 DOH-DXB
  - No bags offered on this itinerary
  - No meals offered on this itinerary
  - No other items offered on this itinerary
- **Seat map** `POST /flights/seat-map`: HTTP 200, 0 seats
  - 0 flight(s) with a seat map of 2 in the itinerary: 
  - No seats returned for this itinerary
  - Errors: seat map on errorDetails dropped: not a flight of this itinerary

### International, one way, 1 adult, 1 child, 1 infant

International one way for 1 adult, 1 child, 1 infant: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. One search segment; one group, journey_indexes [0]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 180 options
  - 180 options in 1 group(s): journey_indexes [0] has 180 options
  - Options by number of flights: 1 flight: 15, 2 flights: 161, 3 flights: 4
  - Airlines in the reply: AI (62 flights), QR (44 flights), IX (30 flights), EK (28 flights), H1 (26 flights), GF (20 flights), EY (16 flights), WY (16 flights), SV (14 flights), SG (13 flights), ET (12 flights), UL (11 flights), TK (10 flights), XY (8 flights), BA (8 flights), MS (6 flights), LH (5 flights), KU (4 flights), SQ (4 flights), AZ (2 flights), J2 (2 flights), FZ (2 flights), CX (2 flights), LX (2 flights), LO (1 flights), HY (1 flights)
  - 1013 fare options in total; 106 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option ef82c5e9… / price 7c8d686b…
  - Repriced option on journey_indexes [0]: 2 flights (QR 4781 DEL-DOH, QR 1006 DOH-DXB); multi-flight reprice: yes
  - Fare Economy Classic PARTIALLY_REFUNDABLE: adult total 19,961, net 19,961; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 0 items
  - 2 flight(s) in segments[]: (journey 0, segment 0) QR 4781 DEL-DOH; (journey 0, segment 1) QR 1006 DOH-DXB
  - No bags offered on this itinerary
  - No meals offered on this itinerary
  - No other items offered on this itinerary
- **Seat map** `POST /flights/seat-map`: HTTP 200, 0 seats
  - 0 flight(s) with a seat map of 2 in the itinerary: 
  - No seats returned for this itinerary
  - Errors: seat map on errorDetails dropped: not a flight of this itinerary

### International, return, 1 adult

International return for 1 adult: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. Two search segments. International return fares are combined: one group [0, 1]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 528 options
  - 528 options in 1 group(s): journey_indexes [0, 1] has 528 options
  - Options by number of flights: 2 flights: 53, 3 flights: 46, 4 flights: 429
  - Airlines in the reply: EY (536 flights), QR (400 flights), GF (280 flights), WY (216 flights), IX (160 flights), EK (92 flights), SV (72 flights), AI (58 flights), SG (38 flights), XY (24 flights), TK (20 flights), UL (16 flights), KU (16 flights), SQ (16 flights), H1 (8 flights), ET (4 flights), J2 (4 flights)
  - 2734 fare options in total; 80 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 000ab253… / price 30a73c30…
  - Repriced option on journey_indexes [0, 1]: 4 flights (QR 4771 DEL-DOH, QR 1022 DOH-DXB, QR 1019 DXB-DOH, QR 4790 DOH-DEL); multi-flight reprice: yes
  - Fare Economy Classic PARTIALLY_REFUNDABLE: adult total 40,311, net 40,311; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 0 items
  - 4 flight(s) in segments[]: (journey 0, segment 0) QR 4771 DEL-DOH; (journey 0, segment 1) QR 1022 DOH-DXB; (journey 1, segment 0) QR 1019 DXB-DOH; (journey 1, segment 1) QR 4790 DOH-DEL
  - No bags offered on this itinerary
  - No meals offered on this itinerary
  - No other items offered on this itinerary
- **Seat map** `POST /flights/seat-map`: HTTP 200, 0 seats
  - 0 flight(s) with a seat map of 4 in the itinerary: 
  - No seats returned for this itinerary
  - Errors: seat map on errorDetails dropped: not a flight of this itinerary

### International, return, 1 adult, 1 child, 1 infant

International return for 1 adult, 1 child, 1 infant: search, reprice the cheapest fare, then the ancillaries and the seat map of the itinerary, book it on hold (no payment), read the booking details and release the hold. Two search segments. International return fares are combined: one group [0, 1]; reprice takes one item.

- **Search** `POST /flights/search`: HTTP 200, 421 options
  - 421 options in 1 group(s): journey_indexes [0, 1] has 421 options
  - Options by number of flights: 2 flights: 53, 3 flights: 42, 4 flights: 326
  - Airlines in the reply: EY (444 flights), QR (320 flights), WY (204 flights), IX (144 flights), GF (124 flights), EK (80 flights), SV (72 flights), AI (54 flights), SG (38 flights), TK (20 flights), SQ (16 flights), H1 (8 flights), ET (4 flights), UL (4 flights), J2 (4 flights)
  - 2098 fare options in total; 64 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 4d6f849d… / price 110de393…
  - Repriced option on journey_indexes [0, 1]: 4 flights (QR 4771 DEL-DOH, QR 1006 DOH-DXB, QR 1019 DXB-DOH, QR 4790 DOH-DEL); multi-flight reprice: yes
  - Fare Economy Classic PARTIALLY_REFUNDABLE: adult total 40,311, net 40,311; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 0 items
  - 4 flight(s) in segments[]: (journey 0, segment 0) QR 4771 DEL-DOH; (journey 0, segment 1) QR 1006 DOH-DXB; (journey 1, segment 0) QR 1019 DXB-DOH; (journey 1, segment 1) QR 4790 DOH-DEL
  - No bags offered on this itinerary
  - No meals offered on this itinerary
  - No other items offered on this itinerary
- **Seat map** `POST /flights/seat-map`: HTTP 200, 0 seats
  - 0 flight(s) with a seat map of 4 in the itinerary: 
  - No seats returned for this itinerary
  - Errors: seat map on errorDetails dropped: not a flight of this itinerary

### Price changed at reprice

The fare went up or down between search and reprice: reprice answers 200 with messages[] (type, option_id, old_value, new_value). Show the new price to the traveller before booking. Captured whenever it happens in a run.

- **Search** `POST /flights/search`: HTTP 200, 166 options
  - 166 options in 1 group(s): journey_indexes [0] has 166 options
  - Options by number of flights: 1 flight: 43, 2 flights: 123
  - Airlines in the reply: AI (95 flights), IX (67 flights), H1 (36 flights), SG (28 flights), EK (20 flights), SQ (18 flights), EY (16 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 692 fare options in total; 37 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 16560204… / price d2f877b1…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price changed since search for option 16560204…: FARE_ALERT 6,004 → 9,004

### Fare attributes per flight (detail: segment)

detail: segment adds segments[] inside every fare option, with the cabin, booking class, fare basis, meal and baggage of each flight. Useful when varies_by_segment is true.

- **Search** `POST /flights/search`: HTTP 200, 215 options
  - 215 options in 1 group(s): journey_indexes [0] has 215 options
  - Options by number of flights: 1 flight: 68, 2 flights: 147
  - Airlines in the reply: AI (107 flights), 6E (66 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 865 fare options in total; 48 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 0cf2ee70… / price c723a668…
  - Repriced option on journey_indexes [0]: 1 flight (6E 46 DEL-BOM); multi-flight reprice: no
  - Fare Series Purchase NON_REFUNDABLE: adult total 1,799, net 1,799; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)

### Search without fare rules (include_fare_rules: false)

include_fare_rules: false leaves the fare_rules table out of the reply and off every fare: a smaller reply. Reprice still returns the final rules.

- **Search** `POST /flights/search`: HTTP 200, 265 options
  - 265 options in 1 group(s): journey_indexes [0] has 265 options
  - Options by number of flights: 1 flight: 81, 2 flights: 184
  - Airlines in the reply: 6E (153 flights), AI (107 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 999 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option f162dc32… / price 488573ec…
  - Repriced option on journey_indexes [0]: 1 flight (6E 46 DEL-BOM); multi-flight reprice: no
  - Fare Series Purchase NON_REFUNDABLE: adult total 1,799, net 1,799; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)

### One airline only (preferred_airlines)

preferred_airlines limits the reply to the airlines named (IATA codes).

- **Search** `POST /flights/search`: HTTP 200, 45 options
  - 45 options in 1 group(s): journey_indexes [0] has 45 options
  - Options by number of flights: 1 flight: 25, 2 flights: 20
  - Airlines in the reply: 6E (65 flights)
  - 147 fare options in total; 6 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option fb24a386… / price a9539734…
  - Repriced option on journey_indexes [0]: 1 flight (6E  354 DEL-BOM); multi-flight reprice: no
  - Fare Regular Fare : adult total 6,646, net 6,646; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)

### Business cabin (cabin_class: 3)

cabin_class 3 asks for business fares. The fare's cabin_class says what was found.

- **Search** `POST /flights/search`: HTTP 200, 109 options
  - 109 options in 1 group(s): journey_indexes [0] has 109 options
  - Options by number of flights: 1 flight: 21, 2 flights: 88
  - Airlines in the reply: AI (111 flights), 6E (32 flights), EK (22 flights), EY (16 flights), SQ (14 flights), WY (2 flights)
  - 388 fare options in total; 23 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option ea748fd6… / price df855794…
  - Repriced option on journey_indexes [0]: 2 flights (6E 850 DEL-BLR, 6E 5031 BLR-BOM); multi-flight reprice: yes
  - Fare Business : Stretch PARTIALLY_REFUNDABLE: adult total 25,096, net 25,096; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)

### Three flights in one journey

A long-haul journey with two connections: one option, three flights, segment_index 0, 1 and 2 inside journey 0.

- **Search** `POST /flights/search`: HTTP 200, 349 options
  - 349 options in 1 group(s): journey_indexes [0] has 349 options
  - Options by number of flights: 1 flight: 2, 2 flights: 116, 3 flights: 231
  - Airlines in the reply: AC (214 flights), LH (130 flights), EK (118 flights), DL (112 flights), KL (69 flights), AF (47 flights), QR (47 flights), AA (28 flights), BA (28 flights), LX (20 flights), UA (20 flights), EY (16 flights), CX (15 flights), AI (14 flights), JL (8 flights), NH (6 flights), TK (6 flights), VS (5 flights), WY (4 flights), ET (4 flights), AM (3 flights), AZ (2 flights), MS (2 flights), BR (2 flights), LO (2 flights), KE (2 flights), WS (1 flights), 9B (1 flights), OS (1 flights)
  - 1862 fare options in total; 135 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option a1095f13… / price 12d9cfd9…
  - Repriced option on journey_indexes [0]: 3 flights (QR 579 DEL-DOH, QR 725 DOH-ORD, QR 9524 ORD-YYZ); multi-flight reprice: yes
  - Fare Economy Classic PARTIALLY_REFUNDABLE: adult total 54,696, net 54,696; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)

### Bags and meals on a low-cost airline

A direct low-cost flight: baggage per journey (journey_index) and meals per flight (journey_index and segment_index), each item with code, label and price.

- **Search** `POST /flights/search`: HTTP 200, 265 options
  - 265 options in 1 group(s): journey_indexes [0] has 265 options
  - Options by number of flights: 1 flight: 81, 2 flights: 184
  - Airlines in the reply: 6E (153 flights), AI (108 flights), IX (60 flights), H1 (37 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1001 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 38b6fe61… / price 6f82ddce…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1463 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 21 items
  - 1 flight(s) in segments[]: (journey 0, segment 0) IX 1463 DEL-NMI
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 11 meals (per flight): (journey 0, segment 0): 11 items

### Seat map with paid and free seats

The seat map of one flight: every seat with its code, row, column, price (amount, 0 = free), availability and position (window, aisle, exit row).

- **Search** `POST /flights/search`: HTTP 200, 265 options
  - 265 options in 1 group(s): journey_indexes [0] has 265 options
  - Options by number of flights: 1 flight: 81, 2 flights: 184
  - Airlines in the reply: 6E (153 flights), AI (108 flights), IX (60 flights), H1 (37 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1001 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 38b6fe61… / price 6f82ddce…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1463 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Seat map** `POST /flights/seat-map`: HTTP 200, 232 seats
  - 1 flight(s) with a seat map of 1 in the itinerary: (journey 0, segment 0) Airbus A32Y, 232 seats
  - 232 seats available of 232; free: 12; paid: 220 (from 300 to 1,700)
  - Window 76, aisle 78, middle 78; exit row 0; extra leg room 0; infant allowed 0

### Book on hold, plain

Hold without GST details and without ancillaries: book with is_hold true, then the booking details with status ONHOLD and pay_till.

- **Search** `POST /flights/search`: HTTP 200, 262 options
  - 262 options in 1 group(s): journey_indexes [0] has 262 options
  - Options by number of flights: 1 flight: 81, 2 flights: 181
  - Airlines in the reply: 6E (153 flights), AI (101 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 990 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 3d7407a1… / price d4c501aa…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR940777, amount 3,002, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR M9V1FE, ticket BX20HJ00761-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Reddy

### Book on hold with GST details

gst_details (name, number, address, email, mobile) put the company on the invoice; details return them.

- **Search** `POST /flights/search`: HTTP 200, 212 options
  - 212 options in 1 group(s): journey_indexes [0] has 212 options
  - Options by number of flights: 1 flight: 68, 2 flights: 144
  - Airlines in the reply: AI (101 flights), 6E (66 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 855 fare options in total; 48 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option ca8fb6f0… / price cfb1ba3d…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR798181, amount 3,002, pay_till given
  - GST details sent: yes; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR B2LIFJ, ticket BX20HJ00751-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Rao

### Book on hold with a seat, a meal and a bag, one flight

One passenger on a one-flight journey chooses a seat and a meal (journey_index and segment_index) and a bag (journey_index only). The booking details list them under the passenger.

- **Search** `POST /flights/search`: HTTP 200, 265 options
  - 265 options in 1 group(s): journey_indexes [0] has 265 options
  - Options by number of flights: 1 flight: 81, 2 flights: 184
  - Airlines in the reply: 6E (153 flights), AI (108 flights), IX (60 flights), H1 (37 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1001 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 38b6fe61… / price 6f82ddce…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1463 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 21 items
  - 1 flight(s) in segments[]: (journey 0, segment 0) IX 1463 DEL-NMI
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 11 meals (per flight): (journey 0, segment 0): 11 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 232 seats
  - 1 flight(s) with a seat map of 1 in the itinerary: (journey 0, segment 0) Airbus A32Y, 232 seats
  - 232 seats available of 232; free: 12; paid: 220 (from 300 to 1,700)
  - Window 76, aisle 78, middle 78; exit row 0; extra leg room 0; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR546075, amount 8,452, pay_till given
  - GST details sent: no; ancillaries selected: 3
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-NMI: segment 0 IX 1463 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR J9968E, ticket BX20HJ00721-1, fare Value X/XNRA015, total 8,452, net 8,452, baggage hand 7kg, checkin 15kg; ancillaries 4
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Verma

### Book on hold with ancillaries on a two-flight journey

Two adults on a connecting journey. The first takes a meal on the first flight only, a different seat on each flight and a bag for the whole journey; the second takes a meal on the second flight only. Shows per-flight (seat, meal) against per-journey (bag) selection.

- **Search** `POST /flights/search`: HTTP 200, 212 options
  - 212 options in 1 group(s): journey_indexes [0] has 212 options
  - Options by number of flights: 1 flight: 68, 2 flights: 144
  - Airlines in the reply: AI (102 flights), 6E (66 flights), IX (60 flights), H1 (37 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 868 fare options in total; 49 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 26227932… / price 0ddf2775…
  - Repriced option on journey_indexes [0]: 2 flights (IX 1067 DEL-IXB, IX 1547 IXB-BOM); multi-flight reprice: yes
  - Fare Family PARTIALLY_REFUNDABLE: adult total 10,232, net 10,232; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 32 items
  - 2 flight(s) in segments[]: (journey 0, segment 0) IX 1067 DEL-IXB; (journey 0, segment 1) IX 1547 IXB-BOM
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 22 meals (per flight): (journey 0, segment 0): 11 items; (journey 0, segment 1): 11 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 370 seats
  - 2 flight(s) with a seat map of 2 in the itinerary: (journey 0, segment 0) Airbus A32N, 186 seats; (journey 0, segment 1) Boeing 7M8, 184 seats
  - 370 seats available of 370; free: 26; paid: 344 (from 300 to 1,700)
  - Window 119, aisle 124, middle 127; exit row 0; extra leg room 0; infant allowed 0
- **Book on hold** `POST /flights/book`: HTTP 200, 2 passengers
  - Booked on hold (is_hold True) with 2 passenger(s): ADULT 2
  - Status ONHOLD, booking_id AIOR142929, amount 17,982, pay_till given
  - GST details sent: no; ancillaries selected: 5
- **Booking details** `POST /flights/booking/details`: HTTP 200, 2 passengers
  - Status ONHOLD, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-BOM: segment 0 IX 1067 DEL-IXB; segment 1 IX 1547 IXB-BOM
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR O9WK2R, ticket BX20HJ00731-1, fare Family E/ECFA000, total 12,266, net 12,266, baggage hand 7kg, checkin 15kg; ancillaries 6
  -   passenger 1 ADULT Priya: CONFIRMED, PNR O9WK2R, ticket BX20HJ00731-2, fare Family E/ECFA000, total 5,716, net 5,716, baggage hand 7kg, checkin 15kg; ancillaries 1

### Direct booking (paid, no hold), plain

Booked directly, without a hold: book with is_hold false, the amount is taken from the agent's balance or credit at once and the booking is ticketed. There is nothing to confirm or release. Details show the PNR and the ticket per passenger and journey.

- **Search** `POST /flights/search`: HTTP 200, 261 options
  - 261 options in 1 group(s): journey_indexes [0] has 261 options
  - Options by number of flights: 1 flight: 80, 2 flights: 181
  - Airlines in the reply: 6E (152 flights), AI (101 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 991 fare options in total; 49 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option cd95720c… / price 4b896bcf…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1038 DEL-NMI); multi-flight reprice: no
  - Fare Value PARTIALLY_REFUNDABLE: adult total 3,002, net 3,002; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book directly (paid)** `POST /flights/book`: HTTP 200, 1 passengers
  - Paid booking (is_hold False) with 1 passenger(s): ADULT 1
  - Status SUCCESS, booking_id AIOR883281, amount 3,002, no pay_till in the reply
  - GST details sent: no; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status SUCCESS, payment SUCCESS, route DOMESTIC
  - Journey 0 DEL-NMI: segment 0 IX 1038 DEL-NMI
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR G3RNVW, ticket BX20HJ00781-1, fare Value X/XNRA015, total 3,002, net 3,002, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Iyer

### Direct booking (paid, no hold) with GST details

As the plain direct booking (paid, no hold), with gst_details for the company invoice.

- **Search** `POST /flights/search`: HTTP 200, 211 options
  - 211 options in 1 group(s): journey_indexes [0] has 211 options
  - Options by number of flights: 1 flight: 67, 2 flights: 144
  - Airlines in the reply: AI (101 flights), 6E (65 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 852 fare options in total; 47 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 7f32397d… / price 75700de3…
  - Repriced option on journey_indexes [0]: 1 flight (QP 1116 DEL-BOM); multi-flight reprice: no
  - Fare Economy PARTIALLY_REFUNDABLE: adult total 5,967, net 5,967; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book directly (paid)** `POST /flights/book`: HTTP 200, 1 passengers
  - Paid booking (is_hold False) with 1 passenger(s): ADULT 1
  - Status SUCCESS, booking_id AIOR875681, amount 5,967, no pay_till in the reply
  - GST details sent: yes; ancillaries selected: 0
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status SUCCESS, payment SUCCESS, route DOMESTIC
  - Journey 0 DEL-BOM: segment 0 QP 1116 DEL-BOM
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR TESTA20261021012051351, ticket 20261065845, fare Publish /, total 5,967, net 5,967, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Rao

### Direct booking (paid, no hold) with a seat, a meal and a bag, one flight

As the hold case on one flight, but booked directly: paid and ticketed at once, no hold.

- **Search** `POST /flights/search`: HTTP 200, 211 options
  - 211 options in 1 group(s): journey_indexes [0] has 211 options
  - Options by number of flights: 1 flight: 67, 2 flights: 144
  - Airlines in the reply: AI (101 flights), 6E (65 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 852 fare options in total; 47 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 9063f430… / price 27199b02…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1465 DEL-BOM); multi-flight reprice: no
  - Fare Value : adult total 6,029, net 6,029; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 55 items
  - 1 flight(s) in segments[]: (journey 0, segment 0) IX 1465 DEL-BOM
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 18 meals (per flight): (journey 0, segment 0): 18 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 176 seats
  - 1 flight(s) with a seat map of 1 in the itinerary: (journey 0, segment 0) 7M8, 176 seats
  - 167 seats available of 176; free: 0; paid: 167 (from 300 to 1,700)
  - Window 53, aisle 56, middle 55; exit row 12; extra leg room 30; infant allowed 0
- **Book directly (paid)** `POST /flights/book`: HTTP 200, 1 passengers
  - Paid booking (is_hold False) with 1 passenger(s): ADULT 1
  - Status SUCCESS, booking_id AIOR583804, amount 11,479, no pay_till in the reply
  - GST details sent: no; ancillaries selected: 3
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status SUCCESS, payment SUCCESS, route DOMESTIC
  - Journey 0 DEL-BOM: segment 0 IX 1465 DEL-BOM
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR F686KA, ticket F686KA, fare Value EC/KNRA000, total 11,479, net 11,479, baggage hand 7kg, checkin 15kg; ancillaries 3
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Menon

### Direct booking (paid, no hold) with ancillaries on a two-flight journey

As the hold case on a two-flight journey, but booked directly: paid and ticketed at once, no hold.

- **Search** `POST /flights/search`: HTTP 200, 261 options
  - 261 options in 1 group(s): journey_indexes [0] has 261 options
  - Options by number of flights: 1 flight: 80, 2 flights: 181
  - Airlines in the reply: 6E (152 flights), AI (101 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1002 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 67155160… / price fe2482ad…
  - Repriced option on journey_indexes [0]: 2 flights (IX 1274 DEL-IXB, IX 1547 IXB-BOM); multi-flight reprice: yes
  - Fare Family : adult total 10,232, net 10,232; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Ancillaries** `POST /flights/ancillaries`: HTTP 200, 66 items
  - 2 flight(s) in segments[]: (journey 0, segment 0) IX 1274 DEL-IXB; (journey 0, segment 1) IX 1547 IXB-BOM
  - 10 bags (per journey): journey 0: 10 items
  -   bags: price from 2,100 to 18,750; free items: 0
  - 32 meals (per flight): (journey 0, segment 0): 16 items; (journey 0, segment 1): 16 items
- **Seat map** `POST /flights/seat-map`: HTTP 200, 346 seats
  - 2 flight(s) with a seat map of 2 in the itinerary: (journey 0, segment 0) 7M8, 162 seats; (journey 0, segment 1) 7M8, 184 seats
  - 338 seats available of 346; free: 2; paid: 336 (from 300 to 1,700)
  - Window 104, aisle 114, middle 114; exit row 20; extra leg room 60; infant allowed 0
- **Book directly (paid)** `POST /flights/book`: HTTP 200, 2 passengers
  - Paid booking (is_hold False) with 2 passenger(s): ADULT 2
  - Status SUCCESS, booking_id AIOR366189, amount 17,782, no pay_till in the reply
  - GST details sent: no; ancillaries selected: 5
- **Booking details** `POST /flights/booking/details`: HTTP 200, 2 passengers
  - Status SUCCESS, payment SUCCESS, route DOMESTIC
  - Journey 0 DEL-BOM: segment 0 IX 1274 DEL-IXB; segment 1 IX 1547 IXB-BOM
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR C3TY9T, ticket C3TY9T, fare Family FM/ECFA000, total 12,266, net 12,266, baggage hand 7kg, checkin 15kg; ancillaries 4
  -   passenger 1 ADULT Priya: CONFIRMED, PNR C3TY9T, ticket C3TY9T, fare Family FM/ECFA000, total 5,516, net 5,516, baggage hand 7kg, checkin 15kg; ancillaries 1

### Hold, then confirm (pay) the hold

Book on hold, then confirm-hold before pay_till: the amount is taken and the booking is ticketed. Details after.

- **Search** `POST /flights/search`: HTTP 200, 211 options
  - 211 options in 1 group(s): journey_indexes [0] has 211 options
  - Options by number of flights: 1 flight: 67, 2 flights: 144
  - Airlines in the reply: AI (101 flights), 6E (65 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 852 fare options in total; 47 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option 1b2c3335… / price f97ac77e…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1235 DEL-BOM); multi-flight reprice: no
  - Fare Value : adult total 6,029, net 6,029; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR669440, amount 6,029, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Confirm the hold** `POST /flights/booking/confirm-hold`: HTTP 200, 1 confirmed
  - Status after confirm-hold: SUCCESS, amount 6,029
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status SUCCESS, payment SUCCESS, route DOMESTIC, pay_till given
  - Journey 0 DEL-BOM: segment 0 IX 1235 DEL-BOM
  -   passenger 0 ADULT Rohan: CONFIRMED, PNR H4JUWG, ticket H4JUWG, fare Value EC/KNRA000, total 6,029, net 6,029, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Trivedi

### Hold, then release the hold

Book on hold, then release: the airline frees the seats and the booking becomes PNR_RELEASED. Details after.

- **Search** `POST /flights/search`: HTTP 200, 262 options
  - 262 options in 1 group(s): journey_indexes [0] has 262 options
  - Options by number of flights: 1 flight: 81, 2 flights: 181
  - Airlines in the reply: 6E (153 flights), AI (101 flights), IX (60 flights), H1 (38 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 991 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 200, 1 items
  - 1 item(s) sent: option d155717c… / price a0425fd8…
  - Repriced option on journey_indexes [0]: 1 flight (IX 1235 DEL-BOM); multi-flight reprice: no
  - Fare Value : adult total 6,029, net 6,029; segments[] in the reply: no (detail=journey)
  - Price unchanged since search (no messages)
- **Book on hold** `POST /flights/book`: HTTP 200, 1 passengers
  - Booked on hold (is_hold True) with 1 passenger(s): ADULT 1
  - Status ONHOLD, booking_id AIOR987370, amount 6,029, pay_till given
  - GST details sent: no; ancillaries selected: 0
- **Release the hold** `POST /flights/booking/release`: HTTP 200, 1 released
  - Status after release: PNR_RELEASED
- **Booking details** `POST /flights/booking/details`: HTTP 200, 1 passengers
  - Status RELEASED, payment PENDING, route DOMESTIC, pay_till given
  - Journey 0 DEL-BOM: segment 0 IX 1235 DEL-BOM
  -   passenger 0 ADULT Rohan: PNR_RELEASED, PNR FUVSKF, ticket FUVSKF, fare Value EC/KNRA000, total 6,029, net 6,029, baggage hand 7kg, checkin 15kg
  - PNR on 1 of 1 passenger-journeys; 1 passenger(s): ADULT Rohan Verma

### Wrong API key

generate-token with a key that does not exist answers 401; nothing else can be called.

- **Generate token** `POST /generate-token`: HTTP 401
  - Failed with HTTP 401: Authentication required (Invalid API key)
  - This reply is the sample: later steps of the case were not called with it.

### Revoked API key

A key revoked by the agent (or by AirIQ) answers 401 at generate-token at once.

- **Generate token** `POST /generate-token`: HTTP 401
  - Failed with HTTP 401: Authentication required (Invalid API key)
  - This reply is the sample: later steps of the case were not called with it.

### A login token instead of an API token

The customer API takes only tokens made by generate-token. A token from the website login answers 401.

- **Search** `POST /flights/search`: HTTP 401
  - Failed with HTTP 401: Authentication required (Invalid token)
  - This reply is the sample: later steps of the case were not called with it.

### Reprice after the search expired

option_id and price_id are good until the search's valid_till. After it reprice refuses them: search again.

- **Search** `POST /flights/search`: HTTP 200, 265 options
  - 265 options in 1 group(s): journey_indexes [0] has 265 options
  - Options by number of flights: 1 flight: 81, 2 flights: 184
  - Airlines in the reply: 6E (153 flights), AI (108 flights), IX (60 flights), H1 (37 flights), SG (32 flights), EK (20 flights), EY (16 flights), SQ (14 flights), QP (6 flights), WY (2 flights), 9I (1 flights)
  - 1001 fare options in total; 50 distinct fare families (fare_ref)
- **Reprice** `POST /flights/reprice`: HTTP 404
  - Failed with HTTP 404: Flight not found (Journey details not found: bbc742b1-36fa-46cb-a7b1-1c6125621c59)
  - This reply is the sample: later steps of the case were not called with it.

### Book after the itinerary expired

An itinerary_id is good until the reprice reply's valid_till. After it book refuses it: reprice again.

- **Book on hold** `POST /flights/book`: HTTP 410
  - Failed with HTTP 410: The itinerary has expired; reprice again
  - This reply is the sample: later steps of the case were not called with it.