Skip to main content
This guide walks you through renting a car from start to finish. Car rental follows the same trip flow as flights and hotels: every offer returned by car_search is already priced and bookable, and its offer_id (the car_* token) goes straight into a trip. There is no car-specific booking call. The one-line version of the flow:
And after the booking, if the customer changes their mind:

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 cars

A search needs five things: where and when the car is collected, when it is returned, the driver’s age, and the driver’s country of residence. The last two change the price and which suppliers will rent at all, so collect them from the user rather than guessing.
A few things to know about the search:
  • Name the place the way a traveler would. Send exactly one of airport_code (an IATA code, the simplest path), place (free text such as “Lyon Part-Dieu”), or geo (coordinates plus a radius, for “near me”). When free text matches several different rental locations, the response carries a candidates list instead of offers. Put those to the user and search again with the chosen name. Never auto-pick one: “Lyon” is an airport, a rail station, and a downtown office that book three different counters.
  • Date-times are branch-local and carry no timezone. Send 2026-11-12T10:00:00, never a Z or an offset. The rental desk works on its own wall clock, and each branch in the response carries its IANA time_zone.
  • Omit drop_off for a round trip and set drop_off_date_time instead. For a one-way rental, send drop_off with its own place and date_time.
  • Offers expire. Each offer carries expires_at, about 30 minutes out. After that, search again.

Reading an offer

Every offer flattens one vehicle, one rate package, and one branch pair into a single bookable line: Amounts are { value, currency, decimal_places, display } in minor units. Show display; compute with value / 10 ** decimal_places.
A branch with requires_flight_number: "always" cannot be booked. Jinko carries no flight number today, so the supplier would refuse the rental. Prefer an offer from another branch.

2) Build the trip

Add the chosen offer to a trip and set travelers in one call. The car_* token goes into trip(add_item) exactly the same way a flight trip_item_token or a hotel htl_* token does. The first traveler is the driver.
A car rental needs contact.title. The honorific of the booking contact (mr, ms, mrs) is required by the rental supplier, and the checkout readiness gate refuses a trip with a car item and no title before any card is charged. It is optional for flight-only and hotel-only trips.
The driver’s age and country of residence are not asked again here. They were baked into the rate at search time, which is why car_search insists on the real values.

3) Checkout

Create the Stripe checkout session:
The checkout_url points at app.gojinko.com/checkout, a Stripe-hosted page Jinko owns. Open the exact string the API returned; never build one yourself. The response also carries expires_at, the deadline on the quoted price, which is a different clock from the checkout link itself. See the flight guide for the full envelope and Errors, after a quote expires for what happens past it. The customer is charged price.pay_now and nothing else. Anything the offer listed as due at the desk, a deposit, or an estimated total is settled between the driver and the rental company at pick-up.

4) User pays

Send the user to checkout_url. They:
  1. Confirm the vehicle, dates, and branches.
  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. The fulfillment states are the same as for hotels: awaiting_payment → preparing → prepared → processing → confirming, ending at one of the terminal states (completed, partial, failed, cancelled, expired_quote, exchange_partial_failure).
Offers with on_request: true settle asynchronously. The supplier confirms availability by hand after the booking is placed, so the trip can sit in confirming for a while rather than seconds. Poll until a terminal state and tell the customer the rental is pending confirmation, not confirmed.

6) Watch the booking land

Poll get_trip until fulfillment.status is terminal. The loop is identical to the hotel guide: break on every terminal state, not just completed and failed. The confirmation lives in bookings[] with the Jinko booking_reference (JNK-XXXXXX). The customer also receives a confirmation email from Jinko carrying the rental company’s own reference, the pick-up branch, and the driver instructions.

7) Cancel a rental

Changing a rental (dates, vehicle, extras) is not offered. The only path to a different rental is to cancel this one and book again with car_search. Cancellation is a two-step flow so the customer sees the fee before anything happens.
1

Look up the booking

Call get_booking with the booking reference and the driver’s last name, and pick the car item’s stable item_id from items[]. The item carries its servicing eligibility and any refusal reason.
2

Preview the fee

Quote the fee in force and the refund it would leave. Nothing is cancelled yet. The response carries a cancellation_id (ccl_...) that binds the later commit to exactly this quote, and an expires_at after which you preview again.
3

Get the customer's confirmation

Show the fee and the refund and get an explicit yes. This ends the rental.
4

Commit

Commit is safe to repeat: a cancellation that already went through is reported as it stands rather than cancelled twice. car_cancel(status) re-reads the latest attempt at any time and can never start a cancellation.
Reading the money on a preview or a commit:
  • fee_known: false means the supplier published no fee schedule we could resolve. The fee and refund fields are then absent, not zero. Say “we will confirm the cancellation fee”. Never present it as free cancellation.
  • refund_pending_review: true means the booking is cancelled but a person still owes the customer the refund answer. Do not quote refund_amount as final.
  • manual_required: true on a preview means it cannot be completed online, for example because the fee could not be established or the rental was changed after it was paid for. refund_review_reason says why. If the customer explicitly agrees to hand it to a Jinko agent, commit with manual_ok: true; the cancellation is then recorded as pending and an agent completes it and settles the refund by hand. Never send manual_ok pre-emptively: it is the customer’s consent, not a retry flag.
A commit can be refused without anything happening, and the answer says why: the quote expired (preview again), the refund moved since the preview (a fresh cancellation_id is returned, show the new figure and commit that one), another cancellation is in flight, or the rental is no longer cancellable. state: "rejected" means the supplier declined and the booking still stands; surface rejected_reason to the customer.

What’s next?