---
title: "Create and manage a trip: add or remove items and set travelers"
method: POST
path: "/v1/trip"
tags: ["Pricing & booking"]
---

# Create and manage a trip: add or remove items and set travelers

`POST /v1/trip`

## Request

- Base URL: `https://api.gojinko.com`
- URL: `https://api.gojinko.com/v1/trip`
- Auth: one of:
  - API key in header `X-API-Key`
  - HTTP bearer

Creates or edits a trip without starting pricing. A new item has no price until it is successfully quoted. Call POST /v1/checkout to start pricing and wait for a checkout result. Polling GET /v1/trip/{trip_id} after creation does not start pricing.

## Request body

- TripRequest
  - `trip_id` string
  - `add_item` object
    - `trip_item_token` string, required
    - `special_requests` string[]: HOTEL ITEMS ONLY. Free-text special requests for the property, one per entry — late arrival, quiet room, high floor, bedding preference, non-smoking room, baby cot, accessibility needs. They apply to the whole stay and are forwarded to the hotel supplier with the booking as REQUESTS ONLY: neither Jinko nor the supplier guarantees them, and a confirmed booking does not mean the hotel will honour them. At most 10 entries of 500 characters each and 1500 characters in total, counted after trimming; blank entries are dropped. Ignored on flight and ground items. Echoed back on the item as `special_requests`, trimmed and without the blank entries (JIN-2499).
  - `remove_item` object
    - `item_id` string, required
  - `upsert_travelers` object
    - `travelers` Traveler[], required: Travelers on the trip (replaces all). Required to complete a booking; the first traveler also supplies the booking contact name.
      - `first_name` string, required: For flights, the airline must be able to print the name on the ticket: Latin letters (accents allowed), spaces, hyphens and apostrophes only. The last name holds at most 29 characters (the airline cannot ticket a longer surname), and first, middle and last name together at most 63. Two travellers in one trip cannot share the same full name. A name that breaks these rules is refused at upsert_travelers or checkout with 400 BAD_REQUEST and `error.field` naming the traveller.
      - `last_name` string, required: For flights, the airline must be able to print the name on the ticket: Latin letters (accents allowed), spaces, hyphens and apostrophes only. The last name holds at most 29 characters (the airline cannot ticket a longer surname), and first, middle and last name together at most 63. Two travellers in one trip cannot share the same full name. A name that breaks these rules is refused at upsert_travelers or checkout with 400 BAD_REQUEST and `error.field` naming the traveller.
      - `date_of_birth` string: Date of birth (YYYY-MM-DD, nothing before or after it). Required for flights, and for a `child` or `infant` staying at a hotel; optional for an adult on a hotel-only trip. For flights it cannot be in the future and must agree with `traveler_type` on the trip's flight dates; otherwise upsert_travelers or checkout answers 400 BAD_REQUEST with `error.field` naming the traveller and field.
      - `gender` 'MALE' | 'FEMALE': Required for flights; optional for hotel-only trips. Accepted in either case (`male` reads as `MALE`).
      - `traveler_type` 'adult' | 'child' | 'infant', required: Accepted in either case (`Adult` reads as `adult`). For flights, the traveller's age on the date the booking ages travellers on decides the type — the trip's first flight, or for some bookings the return flight of a round trip: `adult` 12 or older, `child` 2 to 11, `infant` under 2, and an `infant` must still be under 2 on the trip's last flight. A type the `date_of_birth` contradicts is refused at upsert_travelers (once the trip holds the flight) or at checkout with 400 BAD_REQUEST and `error.field` naming the traveller. A flight searched for another party is re-priced for these travellers at checkout, on the same flights and fare family; when that fare is not sold for them, checkout answers 409 `OFFER_UNAVAILABLE`. Each hotel in the trip is booked with these travellers (a `room_bundle` hotel whose rooms `hotel_room_guests` names is booked for those room guests instead), so they cannot name more adults or more children than its rooms were priced for (the hotel_search `occupancies`: `adults` and `children_ages`), and each child's age at check-in must be one of the priced `children_ages`. The hotel counts a traveller by age at check-in, 18 or older being an adult, and a traveller with no `date_of_birth` as an adult. upsert_travelers or checkout answers 400 BAD_REQUEST naming the first traveller over a count or with an age the room was not priced for; search the hotel again for the party.
      - `nationality` string
      - `passport_number` string
      - `passport_expiry` string: Passport expiry (YYYY-MM-DD, nothing before or after it). For flights it cannot be before the trip's last flight; otherwise upsert_travelers or checkout answers 400 BAD_REQUEST with `error.field` naming the traveller.
      - `passport_country` string
      - `frequent_flyer` FrequentFlyer: Optional per-passenger frequent-flyer membership so airline miles are credited on the booking. Flights only; when present, both airline and number are required.
        - `airline` string, required: IATA code of the loyalty program issuer (e.g. `LH` for Lufthansa Miles & More), not necessarily the operating carrier — alliances credit miles on partner flights.
        - `number` string, required: Membership / account number for that loyalty program.
      - `known_traveler_number` string: US trusted-traveler Known Traveler Number (TSA PreCheck / Global Entry). Flights only; sent to the airline as Secure Flight data so PreCheck eligibility prints on the boarding pass.
      - `known_traveler_issuing_country` string: ISO 3166-1 alpha-2 country that issued the Known Traveler Number. Defaults to `US` downstream; ignored without known_traveler_number.
      - `redress_number` string: DHS redress control number (TRIP program). Flights only; sent to the airline as Secure Flight data.
      - `redress_issuing_country` string: ISO 3166-1 alpha-2 country that issued the redress number. Defaults to `US` downstream; ignored without redress_number.
    - `contact` Contact: Booking contact (email + phone, optionally title). Optional while building the trip, but required before booking.
      - `email` string, email, required: Contact email for booking confirmations. A trip with a flight needs it before payment: without a contact email, checkout answers 422 `MISSING_CUSTOMER_DETAILS` with `email` in `missing_fields`.
      - `phone` string, required: Contact phone in international format: a leading `+` and country code, e.g. `+12025550147`. Spaces, hyphens, dots and parentheses are accepted and removed. A number without the leading `+` is rejected with `INVALID_PHONE_NUMBER`. Required to complete a booking.
      - `title` string: Honorific of the booking contact (e.g. "mr", "ms", "mx"). Free text, resolved downstream per provider. Required to book a car rental; optional otherwise.
  - `hotel_room_guests` HotelRoomGuests: Optional primary adult room-contact overrides keyed by the returned hotel item_id/product_id. Each product array is non-empty and occupancy_number values are unique positive room slots; omitted slots use persisted adult travelers in order with the trip contact email. The trip must already exist because the keys refer to its items.
  - `intent` IntentInput
    - `user_intent` string, nullable: The user's natural-language intent: the Alpic PII-stripped paraphrase when available, else a best-effort fallback to the client-provided NL query.

## Response `200`

The trip

- TripResponse
  - `trip_id` string, required
  - `status` 'draft' | 'quoting' | 'quoted' | 'fulfillment_prepared' | 'fulfilling' | 'fulfilled' | 'partially_fulfilled' | 'failed' | 'cancelled' | 'expired': Where the trip is in its lifecycle, as one value for the whole trip. The booking’s progress after payment is `booking_state` (GET /v1/trip/{trip_id}); the four booking values below (`fulfilling`, `fulfilled`, `partially_fulfilled`, `failed`) are deprecated in favour of it and still sent. `draft`: being built or priced, nothing paid. `fulfilling`: payment was submitted and booking started. Then exactly one outcome: `fulfilled` (`booking_state` `completed`), `partially_fulfilled` (`partial`) or `failed` (`failed`). `cancelled`: replaced by a new trip when it was re-shopped. `expired` is the 24-hour lapse: it is evaluated LAZILY, on the read that first observes it, so this call is where a dead trip becomes visible. Once a trip is expired, adding items, setting travelers and checkout are refused with `TRIP_EXPIRED`; any other state that refuses a write answers `TRIP_STATE_CONFLICT` and names the state here. Start a new trip — a lapsed one cannot be revived. `quoting`, `quoted` and `fulfillment_prepared` are reserved and not currently set; quote progress is in `quote.status`.
  - `actions_performed` string[]
  - `items` TripResponseItem[]
    - `item_id` string
    - `kind` string: What the item is: "flight", "hotel", "car" or "ground". Same field name as on get_trip and checkout.
    - `type` string: Deprecated: use `kind` (same value).
    - `description` string: A summary of the selected item.
    - `offer_id` string: Deprecated: use `trip_item_token` instead. The offer handle this item was created from, exactly as it was submitted to `trip(add_item)`. On a hotel item it is the `htl_…` rate token; on a flight item it is the itinerary id. Two caveats when reconciling: on a hotel whose occupancy the provider re-shopped, this stays the token you SUBMITTED even though the priced rate moved; and a flight added twice on the same itinerary with different fares is de-duplicated by itinerary, so the echo can name the first fare added.
    - `trip_item_token` string: The handle `trip(add_item)` took, echoed verbatim. On a hotel or car item it is the offer’s `trip_item_token` from the search. On a flight item it is the itinerary id and the fare joined by a colon, absent when the fare half was never resolved (a caller-supplied snapshot skips the resolver); read that absence as "the platform cannot name the fare", never as a different fare.
    - `hotel_id` string: The property this hotel item books — the same id `hotel_search` publishes, so an item joins straight back to the search result it came from. Hotel items only.
    - `special_requests` string[]: The special requests submitted with `trip(add_item)` for this hotel item, as stored — trimmed, blank entries dropped — and forwarded to the hotel supplier at booking. Requests only — the hotel may not honour them, and a confirmed booking does not imply it will. Hotel items only; absent when none were given (JIN-2499).
    - `booking_scope` string: `room_bundle` means the submitted hotel offer token covers every room in `rooms`. Absent on every other hotel item, a single room included: read `rooms` for the rooms an item covers, and `booking_scope` only to learn whether one token books them all.
    - `num_rooms` integer: Number of rooms this hotel item covers: 1 for a single room, the bundle size for a room bundle. Hotel items only; absent when the platform cannot state the party the item was priced for.
    - `rooms` HotelBundleRoom[]: One entry per room this hotel item covers, single room or bundle (JIN-2565). Each entry states in `occupancy` the party that room was priced for — adults and children’s ages — so a checkout page can show the guest who the rate is for before payment, and a wrong child age, which changes the price and the room, is caught before the money moves. On a single room the entry’s room, board, refundability and tax lines are the item’s own, the same figures `hotel_terms` states; on a room bundle each entry carries that room’s details from the supplier. The item price remains the authoritative customer total for every room together. Absent when the platform holds no party for the item.
      - `occupancy_number` integer, required: Stable one-based room slot within this bundle.
      - `room_id` string
      - `mapped_room_id` integer
      - `room_name` string
      - `rate_id` string
      - `occupancy` Occupancy, required: The party one room is requested or priced for: the number of adults and the age of each child.
        - `adults` integer, required
        - `children_ages` integer[]
      - `board_type` string
      - `board_name` string
      - `max_occupancy` integer
      - `taxes_and_fees` TaxLine[]
        - `amount` number: Deprecated: use `amount_money` instead. The tax in MAJOR units of `currency`.
        - `currency` string: Deprecated: use `amount_money` instead. The currency of `amount`.
        - `amount_money` object: The tax. When the supplier named no currency for the line, it is the currency the rate is priced in.
          - `value` integer, required: Integer amount in MINOR units at the ISO 4217 digits of `currency`: divide by 10 ** decimal_places to get the amount. Signed where the field says so (a price change delta).
          - `currency` string, required: ISO 4217 currency code.
          - `decimal_places` integer, required: The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3 for BHD/KWD), and the scale of `value`.
          - `display` string, required: The same figure as a string ready to show: the ISO 4217 code, a space, then the amount at `decimal_places`, e.g. "USD 412.50". Show this; compute with `value`.
        - `description` string: The provider’s own wording for the tax. Free text, not a code.
        - `included` boolean: True when the amount is ALREADY inside `total_amount_money`; false when the guest pays it at the property on top. Getting this backwards misquotes the trip.
        - `display` string: Deprecated: use `amount_money` instead. The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. "USD 159.77". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is "JPY 15615.00"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.
      - `policies` HotelBundleRoomPolicy[]
        - `type` string
        - `description` string
        - `fee_amount` number: Deprecated: use `fee_amount_money` instead. Customer policy fee in MAJOR units of `fee_currency`.
        - `fee_currency` string: Deprecated: use `fee_amount_money` instead. The currency of `fee_amount`.
        - `fee_amount_money` object: Customer cancellation or policy fee, with exact minor units and currency precision.
          - `value` integer, required: Integer amount in MINOR units at the ISO 4217 digits of `currency`: divide by 10 ** decimal_places to get the amount. Signed where the field says so (a price change delta).
          - `currency` string, required: ISO 4217 currency code.
          - `decimal_places` integer, required: The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3 for BHD/KWD), and the scale of `value`.
          - `display` string, required: The same figure as a string ready to show: the ISO 4217 code, a space, then the amount at `decimal_places`, e.g. "USD 412.50". Show this; compute with `value`.
      - `is_refundable` boolean
      - `cancellation_policy` CancellationStep[]
        - `cancel_time` string: Deadline after which this tier applies. RFC 3339 with the supplier’s declared UTC offset. Steps whose deadline has no declared timezone are omitted from the ladder — the platform never invents an offset — so a schedule can be shorter than the supplier’s own. Tiers are chronological, earliest first, so the first entry is the deadline that matters.
        - `amount` number: Deprecated: use `amount_money` instead. Read `amount_money`, `percent` or `nights`, whichever this step carries. What the guest is charged on or after `cancel_time`: a sum in MAJOR units of `currency`, a percentage or a number of nights, as `type` says.
        - `currency` string: Deprecated: use `amount_money` instead. The currency of `amount`.
        - `type` string: How the charge is expressed — a sum ("amount", "flat_fee"; read `amount_money`), a percentage ("percent", "percentage"; read `percent`) or a number of nights ("nights"; read `nights`).
        - `display` string: Deprecated: use `amount_money` instead. The same figure as a string ready to show: the ISO 4217 code, a space, then the amount, e.g. "USD 159.77". With decimal_places it is written at exactly that scale (value 1561500, JPY, decimal_places 2 is "JPY 15615.00"); without, at the ISO digits of the currency. Show this; compute with the number. Absent when the figure is not money (a cancellation step expressed as a percent or a number of nights) or could not be read unambiguously.
        - `amount_money` object: What the guest is charged on or after `cancel_time`, when this step is a sum. Absent on a percentage or nights step, and when the supplier named no currency.
          - `value` integer, required: Integer amount in MINOR units at the ISO 4217 digits of `currency`: divide by 10 ** decimal_places to get the amount. Signed where the field says so (a price change delta).
          - `currency` string, required: ISO 4217 currency code.
          - `decimal_places` integer, required: The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3 for BHD/KWD), and the scale of `value`.
          - `display` string, required: The same figure as a string ready to show: the ISO 4217 code, a space, then the amount at `decimal_places`, e.g. "USD 412.50". Show this; compute with `value`.
        - `percent` number: The charge as a percentage of the stay price, when this step is a percentage, on the 0–100 scale the supplier states it in: 50 is half the stay price, 100 the whole of it. Never a 0–1 fraction. Absent otherwise.
        - `nights` number: The charge as a number of nights of the stay, when this step is expressed in nights. Absent otherwise.
      - `free_cancellation_until` string
      - `payment_types` HotelPaymentType[]: How the rate can be settled. Each value appears at most once.
      - `remarks` string
    - `price` number: Deprecated: use `price_money` instead. Item total as a number in major currency units, with currency in the separate `currency` field. Absent until pricing is available; absence does not mean free.
    - `currency` string: Deprecated: use `price_money` instead. ISO currency code for the item price. Absent until pricing is available.
    - `price_display` string: Deprecated: use `price_money` instead. The item price as a string ready to show, when X-Money-Display: iso is requested.
    - `price_money` object: Item total. Absent until pricing is available; absence does not mean free.
      - `value` integer, required: Integer amount in MINOR units at the ISO 4217 digits of `currency`: divide by 10 ** decimal_places to get the amount. Signed where the field says so (a price change delta).
      - `currency` string, required: ISO 4217 currency code.
      - `decimal_places` integer, required: The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3 for BHD/KWD), and the scale of `value`.
      - `display` string, required: The same figure as a string ready to show: the ISO 4217 code, a space, then the amount at `decimal_places`, e.g. "USD 412.50". Show this; compute with `value`.
  - `travelers` TripTraveler[]
    - `traveler_ref` string: The reference to send as `traveler_ref` when selecting a per-traveler ancillary: `pax_<N>`, the traveler's 1-based position in `travelers`.
    - `pax_ref_id` string: Deprecated: use `traveler_ref` instead. Same value.
    - `first_name` string
    - `last_name` string
    - `date_of_birth` string
    - `gender` string
    - `traveler_type` 'adult' | 'child' | 'infant'
    - `passenger_type` string: Deprecated: use `traveler_type` instead. The same type in uppercase.
    - `identity_documents` object: Whether each travel document sent on `upsert_travelers` was saved and will be sent with a flight booking. The passport, Known Traveler and redress numbers themselves are not returned. `upsert_travelers` replaces the whole traveler list, so a document left out of a later upsert reads `absent`.
      - `passport` TripIdentityDocument, required
        - `status` string, required: `absent`: none of the document's fields were sent. `saved`: stored, and sent to the airline with the flight booking (this does not mean the airline accepted it). `invalid`: received, but it cannot be sent as is, so the booking goes ahead without it; `invalid_fields` names what to correct. More values may be added: treat one you do not know as not usable.
        - `invalid_fields` string[]: The missing or failing fields, by their `upsert_travelers` names. Sent only when `status` is `invalid`.
      - `known_traveler_number` TripIdentityDocument, required
        - `status` string, required: `absent`: none of the document's fields were sent. `saved`: stored, and sent to the airline with the flight booking (this does not mean the airline accepted it). `invalid`: received, but it cannot be sent as is, so the booking goes ahead without it; `invalid_fields` names what to correct. More values may be added: treat one you do not know as not usable.
        - `invalid_fields` string[]: The missing or failing fields, by their `upsert_travelers` names. Sent only when `status` is `invalid`.
      - `redress_number` TripIdentityDocument, required
        - `status` string, required: `absent`: none of the document's fields were sent. `saved`: stored, and sent to the airline with the flight booking (this does not mean the airline accepted it). `invalid`: received, but it cannot be sent as is, so the booking goes ahead without it; `invalid_fields` names what to correct. More values may be added: treat one you do not know as not usable.
        - `invalid_fields` string[]: The missing or failing fields, by their `upsert_travelers` names. Sent only when `status` is `invalid`.
  - `contact` object
    - `email` string
    - `phone` string
    - `title` string
  - `hotel_room_guests` HotelRoomGuests: Optional primary adult room-contact overrides keyed by the returned hotel item_id/product_id. Each product array is non-empty and occupancy_number values are unique positive room slots; omitted slots use persisted adult travelers in order with the trip contact email. The trip must already exist because the keys refer to its items.
  - `totals` object
    - `currency` string: Deprecated: use `total_money` instead. ISO currency code of `total`.
    - `total` number: Deprecated: use `total_money` instead. The trip total in major currency units. Absent on a mixed-currency trip.
    - `total_display` string: Deprecated: use `total_money` instead. The trip total as a string ready to show, e.g. "USD 318.40". Absent with `total`.
    - `total_money` object: The trip total. Absent when the trip holds items priced in more than one currency, and while nothing is priced.
      - `value` integer, required: Integer amount in MINOR units at the ISO 4217 digits of `currency`: divide by 10 ** decimal_places to get the amount. Signed where the field says so (a price change delta).
      - `currency` string, required: ISO 4217 currency code.
      - `decimal_places` integer, required: The ISO 4217 digits of `currency` (2 for USD/EUR, 0 for JPY/KRW, 3 for BHD/KWD), and the scale of `value`.
      - `display` string, required: The same figure as a string ready to show: the ISO 4217 code, a space, then the amount at `decimal_places`, e.g. "USD 412.50". Show this; compute with `value`.

## Other responses

- `400`: The request was refused. Invalid traveller names at `upsert_travelers` are refused with `BAD_REQUEST` and `error.field` naming the traveller. **`BAD_REQUEST`** — The request was malformed or failed validation. Fix the request as the message describes; retrying it unchanged cannot succeed.
- `401`: Authentication required
- `402`: Payment required — organization balance exhausted
- `404`: Resource not found
- `409`: The trip refused the write, and nothing was changed — `updated_at` is untouched. **`TRIP_EXPIRED`** — The trip lapsed (24 hours without activity) and no longer accepts writes. Start a new trip and add the items again. A lapsed trip cannot be revived. **`TRIP_STATE_CONFLICT`** — The trip is in a state that refuses this operation: payment already started (`fulfilling`, `fulfilled`, `partially_fulfilled`), or it is `cancelled` or `failed`. Read `status` and act on it: read the trip to find the booking that already exists, or start a new trip. Nothing was written. **`CONFLICT`** — The resource's current state refuses the operation. Re-read the resource and act on what it says — never retry blindly.
- `410`: The offer named in the request is no longer available, or another resource the request names is gone. Tell the two apart by `error.code`. **`OFFER_EXPIRED`** — The search offer is no longer usable: its token expired, or the supplier rejected it as expired or missing during pricing. No payable quote was established. Search again, replace the unavailable item using the latest search result, and check out promptly. Show that the flight offer is no longer available; do not describe this as an established quote expiring (QUOTE_EXPIRED). **`GONE`** — The resource this request names existed and no longer does. Re-acquire it — search again, or check out again to re-quote — then retry with the new identifier. Repeating this request with the same one cannot succeed.
- `422`: The request failed validation. Tell the causes apart by `error.code`. **`BAD_REQUEST`** — The request was malformed or failed validation. Fix the request as the message describes; retrying it unchanged cannot succeed. **`INVALID_PHONE_NUMBER`** — A phone number is not in international format: it has no leading `+` and country code, is not a possible number, or carries an extension. Nothing was written. Resend the number with a leading `+` and country code, for example `+12025550147`. Spaces, hyphens, dots and parentheses are accepted and removed.
- `429`: Rate limit or quota exceeded
- `502`: The travel provider rejected the request, or an upstream call failed
- `503`: No travel provider can serve the request right now
- `504`: The travel provider did not answer in time

---

[API](https://skmtc.dev/gojinko/apis/jinko-public-api.md) - [All operations](https://skmtc.dev/gojinko/apis/jinko-public-api/llms.txt) - [OpenAPI document](https://skmtc.dev/gojinko/apis/jinko-public-api/revisions/ac5046767e4c?raw)
