Skip to main content
Most real journeys involve more than one item. Jinko’s trip is a single booking unit: you can put a flight and a hotel into the same trip, set the travelers once, and check out once. The user pays a single charge and receives a single confirmation with a single Jinko booking reference covering both bookings. This guide builds a week-long Paris trip (a flight from JFK to CDG and a hotel in Paris) end to end with side-by-side examples for SDK, CLI, and MCP. The one-line version of the flow:

Prerequisites

  • A Jinko account and an API key (jnk_t_...). Get one.
  • For the SDK path: Node.js 20 or later, then npm install @gojinko/api-client.
  • For the CLI path: npm install -g @gojinko/cli && jinko auth login --key jnk_t_....
  • For the MCP path: any MCP client connected to https://mcp.builders.gojinko.com/mcp.

1) Discover the flight

Use discovery to compare cached options, then search live fares for the chosen route and dates. The examples below use today’s UTC date plus 60 days for departure and 67 days for return. These are sample dates; replace them with the traveler’s intended local departure and return dates before booking. See the Flight booking guide for the full distinction between route search and offer price-check.
The SDK and CLI calls above use route-search mode. Do not add offer_token to those requests: price-check is a separate mode that accepts a known offer token plus passengers, currency and locale, without route or date fields. If no live fare is returned, stop before deriving the hotel check-in date or building the trip. Read result and surface the returned instruction: no_matches means the search succeeded, so follow the instruction: it asks which filter to relax when the search sent a narrowing filter, otherwise whether to try other dates or airports. A search that could not be completed returns an error instead, which does not mean there are no flights: follow the remedy for the error code; retry a 503 or 504 later with the same filters. Continue only after selecting an available flight fare.

2) Find the hotel

Search hotels from the selected outbound flight’s local arrival date until the return departure date. An overnight flight can arrive the day after departure; confirm check-in against the actual itinerary. Hotel rates are already live offers, no separate price-check step is needed.
If the hotel search returns no rate, stop here and adjust the search. Continue only after choosing an available hotel rate; do not add a missing or null hotel token to the trip.

3) Build the trip with both items

Now the key step. Add the flight to a new trip and set travelers and booking contact in the same call. Then add the hotel to the same trip with a second trip(add_item) call. Both items now live on the same trip and will check out together.
Travelers identify the passengers and guests; the booking contact supplies an email and phone. Both belong to the trip and apply to its flight and hotel items. With REST or the SDK, you can omit upsert_travelers.contact while building the trip, but provide both contact.email and contact.phone before calling checkout. The phone must be 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 + (including a 00 prefix) is rejected with INVALID_PHONE_NUMBER. Passenger details alone are not enough to book either product.With MCP, every upsert_travelers call must include contact. You can add trip items first, then submit travelers and contact together once both are available.
The trip response now contains two items[]: the flight and the hotel. Trip creation does not price them. Treat search prices as provisional and read the authoritative combined total after checkout successfully quotes the trip.

4) Checkout

Once the shared travelers and booking contact are set, call checkout once. You get one checkout_url covering both items.

5) User pays

The user opens checkout_url, sees the flight and the hotel side by side with one total, and enters payment once. Jinko holds the authorization until the bookings settle.

6) Fulfillment

Once the payment is authorized, fulfillment starts for both items. They book in parallel and the booking is completed once both providers confirm. Read booking_state on get_trip for the booking’s progress: fulfillment.status keeps the detailed status behind booking_state, for example preparing, confirming or expired_quote, if you need it for support.
fulfillment is absent until the customer pays. POST /v1/checkout does not create a fulfillment record. It quotes the trip and hands you a checkout_url. The record appears, at awaiting_payment, when the customer presses Pay. Before then get_trip returns quote but no booking_state, no fulfillment and no bookings.fulfilling is a value of the trip’s own top-level status field, not of booking_state. Trip status and booking state explains how the fields relate.

A two-item trip is not atomic

One item can book while the other fails. Handle each item’s outcome independently.When exactly one provider confirms, the trip lands on partial:
  • The item that booked stays booked. Jinko does not roll it back.
  • You are charged only for the item that booked. The rest of the authorization is released.
  • bookings[] contains both entries and does not say which one booked; the webhook below does.
  • A booking.partial webhook fires, carrying the per-item outcome and the amount actually captured.
Deciding what to do next is your call: rebook the failed leg, offer the customer the half that landed, or cancel it. Jinko will not choose for you.

7) Watch the booking land

Poll get_trip, checking booking_state when present. Stop when it reaches a terminal value or the trip’s top-level status is expired. If bookings is present, it lists the flight and hotel entries, failed ones included; booking_state gives the outcome.
Each entry is { item_id, kind, supplier_references }. supplier_references lists the supplier confirmations, each { issuer, reference }, and is [] when none is known. kind is "flight" or "hotel".

What’s next?