Skip to main content
This guide walks you through booking a hotel from start to finish. Hotels skip the separate price-check step you see in flight booking: each rate returned by hotel_search is already a live offer with an htl_* token you can drop straight into a trip. The one-line version of the flow:
hotel_search → trip(add_item + travelers) → book → user pays → get_trip

Prerequisites

  • A Jinko account and an API key (jnk_...). 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_....
  • For the MCP path: any MCP client connected to https://mcp.builders.gojinko.com/mcp.

1) Search hotels

Search live inventory for the destination, dates, and occupancy. Hotel rates returned here are already priced and bookable.
import { createJinkoClient } from '@gojinko/api-client'

const client = await createJinkoClient({ apiKey: process.env.JINKO_API_KEY })

const result = await client.hotelSearch({
  destination: { query: 'Paris' },
  checkin: '2026-07-15',
  checkout: '2026-07-18',
  adults: 2,
})

const hotel = result.hotels[0]
const rate = hotel.rooms[0].rates[0]
console.log(hotel.name, rate.offer_id, rate.total_amount)
The destination field accepts five shapes (free-text query, city plus country code, lat/lng with optional radius, place ID, or a list of hotel IDs). Use whichever matches what you have.

2) Build the trip

Add the chosen rate to a trip and set travelers in one call. The hotel offer_id (the htl_* token) goes into trip(add_item) exactly the same way a flight trip_item_token does.
const trip = await client.trip({
  add_item: { trip_item_token: rate.offer_id },
  upsert_travelers: {
    travelers: [{
      first_name: 'Jane',
      last_name: 'Doe',
      date_of_birth: '1990-01-15',
      gender: 'FEMALE',
      passenger_type: 'ADULT',
    }],
    contact: {
      email: 'jane@example.com',
      phone: '+33612345678',
    },
  },
})
const tripId = trip.trip_id

3) Checkout

Create the Stripe checkout session:
const { checkout_url } = await client.book(tripId)
console.log('Open in browser:', checkout_url)
The checkout_url points at app.gojinko.com/checkout, a Stripe-hosted page Jinko owns.

4) User pays

Send the user to checkout_url. They:
  1. Confirm the hotel, dates, and room.
  2. Enter payment.
  3. Stripe holds the authorization.

5) Fulfillment is automatic

Once the user pays, Stripe webhooks trigger fulfillment on the API. No client-side confirm step is needed. Fulfillment states (get_trip → fulfillment.status):
StateMeaning
pendingPayment cleared, booking not yet attempted
fulfillingCalling the hotel provider (typically seconds)
completedReservation confirmed, booking_ref populated
failedProvider rejected (rare). Refund is issued automatically.

6) Watch the booking land

Poll get_trip until fulfillment.status is terminal:
async function waitForBooking(client, tripId: string) {
  while (true) {
    const trip = await client.getTrip(tripId)
    if (trip.fulfillment?.status === 'completed') {
      console.log('Booked! Ref:', trip.bookings[0].booking_ref)
      return trip
    }
    if (trip.fulfillment?.status === 'failed') {
      throw new Error('Booking failed, refund in progress')
    }
    await new Promise(r => setTimeout(r, 5000))
  }
}

What’s next?

  • Add a flight to the trip: see the Flight + Hotel guide for one trip with two items and one Stripe checkout.
  • Flight-only booking: see the Flight booking guide.
  • Search by location, chain, or amenities: the hotel_search tool reference covers every filter (star rating, hotel type, chain, facilities, geo radius).
  • Lookup a booking after the fact: get_booking finds a booking by reference and last name without needing a login.
  • Troubleshooting: Errors has the full status-code reference.