> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dev.gojinko.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Flight AI search

> Search flights from the traveler's own words over REST: send one sentence, answer the questions it asks, refine with follow-ups, and book a fare.

Flight AI search takes the traveler's request as written, for example "I want to go skiing over the Christmas holidays, any good destinations and flights from San Francisco?", and answers with bookable options, priced for the travelers of the request, and a reply to show. When the destination is a kind of place, such as skiing or a beach, the options cover several destinations that fit. When the dates are a window, the options cover one or more days of it. When something is missing, the answer asks for it. The traveler can then refine the search in the same conversation.

> [!WARNING]
>
> Flight AI search is in preview. The API may change.

## How it differs from flight search

| | [`POST /v1/flight_search`](https://docs.dev.gojinko.com/api/flight-search) | `POST /v1/flight_ai_search` |
| - | - | - |
| Input | Structured fields: route, dates, passengers, filters. | The traveler's sentence, as `text`. |
| Dates | Exact dates. | Exact dates, or a window ("in March", "around March 20"); the options then cover one or more days of the window. |
| Destination | Required. | Optional: without one, the options cover several destinations from the origin. |
| Missing information | `422` for a missing required field. | A question to show the traveler (`status: "input_required"`). |
| Follow-ups | Each call stands alone. | A conversation (`context_id`) keeps what was said, so "nonstop only" refines the last search. |
| Results | Offers with their fares. | Options with their fares, `groups` to present them, plus `message`, `criteria` and `notes`. |
| Booking | `trip_item_token` → trip → checkout. | The same, from an option's fare. |

## The flow

```mermaid theme={null}
sequenceDiagram
  participant App as Your app
  participant Jinko
  App->>Jinko: POST /v1/flight_ai_search {text, timezone}
  alt something is missing
    Jinko-->>App: 200 input_required + question
    App->>Jinko: POST /v1/flight_ai_search {text: answer, context_id}
  end
  alt the turn ends within 20 s
    Jinko-->>App: 200 completed + options
  else the search takes longer (most turns)
    Jinko-->>App: 202 working + Location
    App->>Jinko: GET /v1/flight_ai_search/tasks/{task_id}
    Jinko-->>App: 200 completed + options
  end
  App->>Jinko: POST /v1/trip {add_item: {trip_item_token}}
  App->>Jinko: POST /v1/checkout {trip_id}
```

1. **Send the sentence.** One call with `text` and the traveler's `timezone`.
2. **Answer questions.** An `input_required` answer carries a question; send the traveler's answer with the same `context_id`. See [Conversations](https://docs.dev.gojinko.com/ai/flight-search/conversations.md).
3. **Get the options.** A turn that searches usually takes 10 to 60 seconds, longer than the 20 seconds the call waits, so expect `202` first. Read the task until it ends, or stream it. See [Waiting for results](https://docs.dev.gojinko.com/ai/flight-search/waiting-for-results.md).
4. **Refine.** "nonstop only", "make it Porto instead", "show me more": each follow-up goes in the same conversation.
5. **Book.** Add a fare's `trip_item_token` to a trip and check out before its `expires_at`.

## Quickstart

Flight AI search is served on production only, at `https://api.gojinko.com`, with a production API key; the sandbox does not serve it.

The request is the traveler's own words, in any language. This one asks, in Chinese, for ski destinations and flights from San Francisco over the Christmas holidays:

```bash theme={null}
curl https://api.gojinko.com/v1/flight_ai_search \
  --header "X-API-Key: $JINKO_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "text": "我圣诞节假期想去滑雪，有没有好的目的地和航班推荐，从旧金山出发。",
    "timezone": "America/Los_Angeles"
  }'
```

The search is still running after 20 seconds, so the call answers `202` with the task to read (`Location`, `Retry-After: 2`) and the early reply (other fields left out):

```json theme={null}
{
  "context_id": "ctx_mvtx944haeb8159748fdb024",
  "task_id": "atk_mvtx944t0483d649d5f90257",
  "status": "working",
  "message": "Looking for destinations from San Francisco, leaving between 20 Dec 2026 and 27 Dec 2026, staying 7 days."
}
```

Read the task until `status` is no longer `working`:

```bash theme={null}
curl https://api.gojinko.com/v1/flight_ai_search/tasks/atk_mvtx944t0483d649d5f90257 \
  --header "X-API-Key: $JINKO_API_KEY"
```

The answer, with one option, one fare and two destinations of the group kept. Skiing became a `theme` destination searched at ski destinations, the Christmas holidays a departure window, and the trip a round trip with a 7-day stay, because no return was given:

```json theme={null}
{
  "context_id": "ctx_mvtx944haeb8159748fdb024",
  "task_id": "atk_mvtx944t0483d649d5f90257",
  "status": "completed",
  "message": "70 bookable options for San Francisco → ski destinations, leaving between 20 Dec 2026 and 27 Dec 2026, staying 7 days, 1 adult. Best match: 86.57 USD in total, nonstop.",
  "criteria": {
    "intent": {
      "user_intent": "I want to go skiing for the Christmas holidays, are there any good destination and flight recommendations, departing from San Francisco."
    },
    "origins": [
      {
        "code": "SFO",
        "name": "San Francisco",
        "type": "city",
        "country_code": "US"
      }
    ],
    "currency": "USD",
    "departure": {
      "window": {
        "end": "2026-12-27",
        "start": "2026-12-20"
      }
    },
    "stay_days": 7,
    "trip_type": "roundtrip",
    "passengers": {
      "adults": 1,
      "infants": 0,
      "children": 0
    },
    "destinations": [
      {
        "code": "BOI",
        "name": "ski destinations",
        "type": "theme",
        "country_code": null
      }
    ]
  },
  "notes": [
    {
      "kind": "default_passengers",
      "text": "No travellers were given; priced for one adult."
    },
    {
      "kind": "default_stay",
      "text": "No return date or trip length was given; a 7-day stay was searched.",
      "stay_days": 7
    }
  ],
  "options": [
    {
      "why": "Best match; nonstop",
      "legs": [
        {
          "index": 1,
          "stops": 0,
          "origin": {
            "code": "SFO",
            "airport": "SFO"
          },
          "arrival": "2026-12-25T01:03:00",
          "segments": [
            {
              "origin": "SFO",
              "arrival": "2026-12-25T01:03:00",
              "departure": "2026-12-24T21:23:00",
              "destination": "DEN",
              "flight_number": "F94310",
              "duration_minutes": 160,
              "marketing_carrier": "F9"
            }
          ],
          "departure": "2026-12-24T21:23:00",
          "destination": {
            "code": "DEN",
            "airport": "DEN"
          },
          "duration_minutes": 160
        },
        {
          "index": 2,
          "stops": 0,
          "origin": {
            "code": "DEN",
            "airport": "DEN"
          },
          "arrival": "2026-12-31T20:28:00",
          "segments": [
            {
              "origin": "DEN",
              "arrival": "2026-12-31T20:28:00",
              "departure": "2026-12-31T18:32:00",
              "destination": "SFO",
              "flight_number": "F91093",
              "duration_minutes": 176,
              "marketing_carrier": "F9"
            }
          ],
          "departure": "2026-12-31T18:32:00",
          "destination": {
            "code": "SFO",
            "airport": "SFO"
          },
          "duration_minutes": 176
        }
      ],
      "fares": [
        {
          "total": {
            "amount": 86.57,
            "currency": "USD"
          },
          "brand_name": "BASIC FARE",
          "changeable": false,
          "expires_at": "2026-10-29T20:29:06.884909139Z",
          "priced_for": {
            "adults": 1,
            "infants": 0,
            "children": 0
          },
          "refundable": false,
          "cabin_class": "economy",
          "trip_item_token": "offer__17080dfd:0-1-0",
          "price_per_person": {
            "amount": 86.57,
            "currency": "USD"
          },
          "checked_bag_included": false
        }
      ],
      "score": 100,
      "option_id": "s1_1",
      "trip_type": "roundtrip"
    }
  ],
  "groups": [
    {
      "kind": "per_destination",
      "rows": [
        {
          "dates": {
            "return": "2026-12-31",
            "departure": "2026-12-24"
          },
          "summary": "86.57 USD for the party, nonstop",
          "option_id": "s1_1",
          "destination": {
            "code": "DEN",
            "name": "DEN",
            "type": "city",
            "country_code": null
          },
          "live_cheapest_total": {
            "amount": 86.57,
            "currency": "USD"
          }
        },
        {
          "dates": {
            "return": "2026-12-30",
            "departure": "2026-12-23"
          },
          "summary": "237.36 USD for the party, 1 stop each way",
          "option_id": "s2_1",
          "destination": {
            "code": "SLC",
            "name": "SLC",
            "type": "city",
            "country_code": null
          },
          "live_cheapest_total": {
            "amount": 237.36,
            "currency": "USD"
          }
        }
      ],
      "title": "San Francisco to DEN or SLC or BOI or GEG or RNO or BZN or YVR or HDN or ASE or YYC or GVA or ZRH or MUC or INN",
      "origin": {
        "code": "SFO",
        "name": "San Francisco",
        "type": "city",
        "country_code": "US"
      },
      "group_id": "g_1"
    }
  ],
  "has_more": true,
  "charge": {
    "turn": 1,
    "llm_usd": 0.006647,
    "api_usd": 0.141,
    "total_usd": 0.147647,
    "currency": "USD"
  }
}
```

## The request

| Field | Required | Meaning |
| - | - | - |
| `text` | Yes | The traveler's message, 1 to 2000 characters: a request, an answer to a question, or a follow-up. |
| `timezone` | Yes | The traveler's IANA time zone, such as `Europe/Paris`. Relative dates ("next Friday", "in March") are computed in it. |
| `context_id` | No | The conversation to continue, from an earlier answer. Omit it to start a new one. |
| `task_id` | No | The task of that conversation the message answers. Usually omitted; see [Conversations](https://docs.dev.gojinko.com/ai/flight-search/conversations.md#conversations-and-tasks). |
| `currency` | No | The currency of the prices, ISO 4217 (`EUR`). Without it, prices are in `USD`. A budget the traveler states in a currency ("under 300 EUR") sets the currency of the search. |

Optional headers: `Prefer: wait=N` to change the 20-second wait, `Accept: text/event-stream` to stream, and `Idempotency-Key` to retry safely. See [Waiting for results](https://docs.dev.gojinko.com/ai/flight-search/waiting-for-results.md).

## The answer

| Field | Meaning |
| - | - |
| `context_id` | The conversation. Send it with the traveler's next message. |
| `task_id` | This search. Use it to read, stream or cancel it. |
| `status` | `working`, `input_required`, `completed`, `failed` or `canceled`. See [Statuses and errors](https://docs.dev.gojinko.com/ai/flight-search/statuses-and-errors.md). |
| `message` | The reply to show the traveler, in English. It says what was searched, for whom, and the price of the best match. |
| `question` | With `input_required`: what is missing, one of `origin`, `which_place`, `dates`, `passengers`, `group_too_large`, `contradiction`. See [Answer a question](https://docs.dev.gojinko.com/ai/flight-search/conversations.md#answer-a-question). |
| `question_options` | With some questions: the choices to show, each `value`, `label` and an optional `detail`. Send the chosen `value` back as `text`. |
| `criteria` | What was searched: `trip_type`, `origins`, `destinations`, `legs`, `departure`, `return`, `stay_days`, `passengers`, `priority`, `currency`, and the filters in the [`flight_search`](https://docs.dev.gojinko.com/api/flight-search) field names. |
| `notes` | Assumptions and caveats, each with a `kind`. See [Notes](https://docs.dev.gojinko.com/ai/flight-search/conversations.md#notes). |
| `options` | Every itinerary of the answer, each priced for the travelers of the request, with bookable fares. See [Options](#options). |
| `groups` | How to present the options. See [Groups](#groups). |
| `has_more` | More options of the same search are available; the traveler can ask for more in the same conversation. |
| `charge` | What the turn costs, on the JSON answer of a turn that has ended. See [Charges](#charges). |
| `error` | With `failed`: `code` and `message`. |
| `superseded_by` | With `canceled`: the task that replaced this one. |

Money is `{"amount": 3412, "currency": "EUR"}`, with `amount` in major units of the currency.

### Options

Each option is one itinerary, priced for the travelers of the request with every filter applied, and bookable before each fare's `expires_at`.

| Field | Meaning |
| - | - |
| `option_id` | The option's id in this answer. `groups` reference options by it. |
| `trip_type` | `oneway`, `roundtrip` or `multi_city`. |
| `legs` | 1 for one way, 2 for a round trip, 2 to 4 for a multi-city trip. Each leg has `origin`, `destination`, the local `departure` and `arrival`, `duration_minutes`, `stops` and `segments`. |
| `legs[].segments` | Each flight: `marketing_carrier`, `flight_number`, `origin`, `destination`, local `departure` and `arrival`, `duration_minutes`, `layover_minutes` before the next flight, and `operating_carrier` when it differs. |
| `fares` | The bookable fares, cheapest first. |
| `score` | 0 to 100, how well the option fits the request, relative to the other options of the answer. |
| `why` | A short reason, such as `Best match; nonstop` or `7 EUR more than the best match; 1 stop each way; checked bag included`. Stops read per direction: `1 stop each way`, `1 stop out, nonstop back`. |

Each fare of an option:

| Field | Meaning |
| - | - |
| `trip_item_token` | Add it to a trip to book this fare. See [Book a result](#book-a-result). |
| `brand_name`, `cabin_class` | The fare's brand (`Economy Light`) and cabin (`economy`, `premium_economy`, `business`, `first`). |
| `total` | The price for every traveler in `priced_for`. |
| `price_per_person` | The price for one traveler. |
| `priced_for` | The travelers `total` is for: `adults`, `children`, `infants`. |
| `expires_at` | The last moment the token can be added to a trip. |
| `refundable`, `changeable`, `checked_bag_included` | The fare's conditions. |
| `carry_on_baggage`, `included_baggage` | The baggage allowance in words, such as `1 × 23 kg`, when it is known. |

### Groups

`groups` say how to present the options. Each group lists options by `option_id`, so an option shows once in `options` and can appear in several groups.

| `kind` | When | Fields |
| - | - | - |
| `shortlist` | Always, as the last group: the bookable options, best first. | `title`, `route` (`null` when the options cover several routes or a multi-city trip), `dates` (`null` when the options differ in dates), `option_ids`. |
| `per_destination` | The request named several destinations, or none. | `title`, `origin`, `rows[]` with one row per destination: `destination`, `dates`, `option_id` (the best option, or `null`), `live_cheapest_total`, `empty_reason` when `option_id` is `null`, and `summary`. |

A month search, "the cheapest day from Amsterdam to Lisbon in March 2027", answers options for several days of the month:

```json theme={null}
{
  "groups": [
    {
      "group_id": "g_1",
      "kind": "shortlist",
      "title": "Bookable options",
      "route": null,
      "dates": null,
      "option_ids": ["s1_1", "s3_1", "s2_1"]
    }
  ]
}
```

Options `s1_1`, `s2_1` and `s3_1` are for March 9, 16 and 23; each carries its dates and its fares for the travelers of the request.

## What the search understands

| The traveler says | In `criteria` | What comes back |
| - | - | - |
| A city: "from Paris" | `origins[]` with `type: "city"` and the city code (`PAR`) | Options from any airport of the city. |
| An airport: "from Orly", "CDG" | `type: "airport"` | Options from that airport; several airports ("JFK or Newark") can be named. |
| A country: "to Thailand" | `type: "country"` | Options for cities in the country. When no city can be chosen, the answer asks which city (`which_place`). |
| A region with named airports: "Puglia" (Bari, Brindisi) | `type: "region"` | Options to any of the named airports. |
| A kind of trip instead of a place: "skiing at Christmas", "somewhere warm in February" | `destinations[]` with `type: "theme"` and `name` ("ski destinations") | Options at destinations that fit it, with a `per_destination` group. When none can be chosen, the answer asks where to go (`which_place`). |
| No destination: "where can I fly from Paris in March?" | No `destinations` | Options for several destinations from the origin, with a `per_destination` group. |
| Several destinations: "Lisbon or Porto" | `destinations[]` | A `per_destination` group with one row for each destination: its best option, or an `empty_reason` when none came back. |
| Exact dates: "on October 3, back October 17" | `departure.date`, `return.date` | Options for those dates. |
| A month or a range: "in March", "between May 1 and 15" | `departure.window` | Options for one or more days of the window, each with its dates. When only the first day could be searched, `notes` says so (`no_fares`). |
| Around a date: "around March 20" | `departure.window` of 3 days on each side, or of the days the traveler gives ("give or take 2 days"), and `flexibility_days` | Options for one or more days of the window. |
| No dates | `departure.window` of the next 90 days | Options for one or more days of the next 90 days; `notes` says so (`default_window`). |
| A trip length: "a week in May", "5 to 7 days" | `stay_days` | Round-trip options; each return follows its departure by the stay. |
| Days of the week: "a long weekend in early December", "a weekend in June", "leaving on a Friday in March" | `departure.window` and `departure.weekdays`; `stay_days: 3` for a long weekend, `stay_days: 2` for a weekend | Options leaving only on those days: Thursday or Friday for a long weekend, back on Sunday or Monday; Friday for a weekend, back on Sunday. |
| No return and no trip length, for a holiday or a trip asked as a round trip: "over the Christmas holidays", "a ski trip", "round trip in May" | `trip_type: "roundtrip"`, `stay_days: 7` | Round-trip options with a 7-day stay; `notes` says so (`default_stay`). |
| No return and no trip length otherwise | `trip_type: "oneway"` | One-way options, without a question. |
| Several flights: "Paris to Rome on December 10, then Milan to Paris on December 17" | `legs[]`, `trip_type: "multi_city"` | Options for the whole itinerary. Each leg needs a date. |
| Travelers: "2 adults and a child of 5", "4 passengers" | `passengers` | Fares priced for all travelers. A count without a split is taken as adults; no count is 1 adult. `notes` says so. |
| Cabin: "business class" | `cabin_class` | Only options in that cabin. |
| Stops: "nonstop", "at most one stop" | `max_stops` | Only options with that many stops or fewer. |
| Airlines: "on Air France", "not on Ryanair" | `include_carriers`, `exclude_carriers` | Only options on, or not on, those airlines. |
| Baggage: "with a checked bag" | `checked_bag_included` | Only fares with a checked bag. |
| Fare conditions: "refundable", "changeable" | `refundable_only`, `changeable_only` | Only fares with those conditions. |
| Times: "leaving after 6 PM", "back before noon" | `departure_time_range`, `arrival_time_range`, `return_departure_time_range`, `return_arrival_time_range` | Only options in those time ranges. |
| Connections: "via Dubai", "not through London", "layovers under 2 hours", "under 15 hours in total" | `via_airports`, `exclude_via_airports`, `connection_time_max_minutes`, `max_total_duration_minutes` | Only options that meet those connection conditions. |
| Budget: "under 300 EUR in total", "200 EUR per person" | `budget` with `scope` `total` or `per_person` | Only options within the budget for the whole party; a per-person budget counts the travelers with a seat. |
| Wishes without a fixed rule: "ideally nonstop", "preferably on KLM" | Not a filter | The order of the options. |
| What matters most: "the cheapest", "the fastest", "fewest connections" | `priority`: `price`, `duration`, `connections`, `schedule` or `balanced` | The order of the options. With none stated, `priority` is left out of `criteria` and the options are ordered by price with each stop counted as 15% more of it: a nonstop comes first while it costs at most 15% more per stop it saves. |
| Miles or points: "with my miles" | Not searched | Cash fares; `notes` says so (`not_supported`). |
| Price tracking: "watch this route", "should I wait?" | Not set up | Options as for any request; `notes` says so (`monitoring_not_set_up`). |

Every filter applies as the traveler stated it. No filter is relaxed: when nothing meets them, the answer says so. See [When nothing matches](https://docs.dev.gojinko.com/ai/flight-search/conversations.md#when-nothing-matches).

`message` is always in English; translate it in your app if your traveler reads another language.

## Book a result

A fare is booked like any flight fare: add its `trip_item_token` to a trip, add the travelers and contact, then check out, before the fare's `expires_at`.

```bash theme={null}
curl https://api.gojinko.com/v1/trip \
  --header "X-API-Key: $JINKO_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"add_item": {"trip_item_token": "offer_7f3a9c21_1b2c3d4e:trip_item_0"}}'
```

* `total` is the price for every traveler in `priced_for`, in `currency`.
* `expires_at` is at most 75 minutes after the search. After it, the token is refused with `410` `OFFER_EXPIRED` (see [Errors](https://docs.dev.gojinko.com/concepts/errors.md)). Send a message in the same conversation to search again, and book from the newest answer.

See [Flights](https://docs.dev.gojinko.com/guides/flight-booking.md#book) for travelers, fares, baggage and seats, and [Trips and checkout](https://docs.dev.gojinko.com/guides/trips-and-checkout.md) for the rest of the booking.

## Charges

Each turn is charged. `llm_usd` is the language-model part of the charge, `api_usd` the flight search part, and `total_usd` their sum, in USD.

A question runs no search, so its `api_usd` is `0`. The JSON answer of a turn that has ended carries its charge:

```json theme={null}
{
  "charge": { "turn": 1, "llm_usd": 0.0058, "api_usd": 0.032, "total_usd": 0.0378, "currency": "USD" }
}
```

`turn` is the message of the conversation the charge is for, from 1: the first message is 1 and each next message adds 1, whether it answers a question or asks for something new. A `working` answer and the events of a stream carry no `charge`: read the task once the turn has ended. A message is refused with `402` when your organization's balance is below what a turn needs; see [HTTP statuses](https://docs.dev.gojinko.com/ai/flight-search/statuses-and-errors.md#http-statuses).

## Next

* [Conversations](https://docs.dev.gojinko.com/ai/flight-search/conversations.md): questions, follow-ups, corrections and expiry.
* [Waiting for results](https://docs.dev.gojinko.com/ai/flight-search/waiting-for-results.md): `202`, reading the task, streaming, cancel and retries.
* [Statuses and errors](https://docs.dev.gojinko.com/ai/flight-search/statuses-and-errors.md): every status, failure code and HTTP status.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.