@gojinko/plugin 2.28.0 → 2.29.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jinko",
3
- "description": "Search flights, book trips, and manage bookings with the Jinko Travel API. Connects to the Jinko MCP server for live flight pricing, trip management, and payment.",
4
- "version": "2.28.0",
3
+ "description": "Search flights, hotels and car rentals, book trips, and manage bookings with the Jinko Travel API. Connects to the Jinko MCP server for live pricing, trip management, cancellation and payment.",
4
+ "version": "2.29.1",
5
5
  "author": {
6
6
  "name": "Jinko",
7
7
  "url": "https://gojinko.com"
@@ -12,6 +12,8 @@
12
12
  "keywords": [
13
13
  "travel",
14
14
  "flights",
15
+ "hotels",
16
+ "car-rental",
15
17
  "booking",
16
18
  "mcp"
17
19
  ]
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "jinko",
3
- "description": "Search flights, book trips, and manage bookings with the Jinko Travel API. Connects to the Jinko MCP server for live flight pricing, trip management, and payment.",
4
- "version": "2.28.0",
3
+ "description": "Search flights, hotels and car rentals, book trips, and manage bookings with the Jinko Travel API. Connects to the Jinko MCP server for live pricing, trip management, cancellation and payment.",
4
+ "version": "2.29.1",
5
5
  "author": {
6
6
  "name": "Jinko",
7
7
  "url": "https://gojinko.com"
@@ -12,6 +12,8 @@
12
12
  "keywords": [
13
13
  "travel",
14
14
  "flights",
15
+ "hotels",
16
+ "car-rental",
15
17
  "booking",
16
18
  "mcp"
17
19
  ],
@@ -19,8 +21,8 @@
19
21
  "mcpServers": "./.mcp.json",
20
22
  "interface": {
21
23
  "displayName": "Jinko Travel",
22
- "shortDescription": "Flight search, booking, and trip management",
23
- "longDescription": "Search flights, compare prices, book trips with ancillaries, and manage refunds using the Jinko Travel API. Supports live pricing from multiple airlines via Sabre and TravelFusion.",
24
+ "shortDescription": "Flight, hotel and car-rental search, booking, and trip management",
25
+ "longDescription": "Search flights, hotels and car rentals, compare prices, book trips with ancillaries, and manage cancellations and refunds using the Jinko Travel API. Live flight pricing from multiple airlines via Sabre and TravelFusion.",
24
26
  "developerName": "Jinko",
25
27
  "category": "Productivity",
26
28
  "capabilities": [
@@ -31,7 +33,9 @@
31
33
  "defaultPrompt": [
32
34
  "Find the cheapest flights from Paris to New York next month",
33
35
  "Book a round-trip flight from London to Tokyo",
34
- "Can I get a refund on booking ORD-123?"
36
+ "Find a hotel near the Colosseum in Rome for three nights in May",
37
+ "Rent a compact car at Lyon airport for the weekend, driver aged 35",
38
+ "Can I get a refund on booking JNK-A7B3X9?"
35
39
  ],
36
40
  "brandColor": "#2563EB"
37
41
  }
package/README.md CHANGED
@@ -1,10 +1,10 @@
1
1
  # Jinko Travel Plugin
2
2
 
3
- Plugin for **Claude Code** and **OpenAI Codex** that enables flight search, trip booking, and booking management via the Jinko Travel API.
3
+ Plugin for **Claude Code** and **OpenAI Codex** that enables flight, hotel and car-rental search, trip booking, and booking management via the Jinko Travel API.
4
4
 
5
5
  ## What's included
6
6
 
7
- - **6 skills**: search-flights, search-hotels, book-trip, manage-booking, account, cli
7
+ - **7 skills**: search-flights, search-hotels, search-cars, book-trip, manage-booking, account, cli
8
8
  - **MCP server config**: connects to `mcp.builders.gojinko.com`
9
9
  - **Dual-platform support**: works with both Claude Code and Codex CLI
10
10
 
@@ -40,10 +40,11 @@ codex plugin install @gojinko/plugin
40
40
  |-------|-------------|---------------|
41
41
  | `jinko:search-flights` | Find flights, explore destinations, compare prices | "Find flights from Paris to Tokyo in June" |
42
42
  | `jinko:search-hotels` | Search live hotel inventory and rates by destination, dates, and occupancy — or look up a hotel by name | "Find hotels in Tokyo for 2 nights in June" |
43
- | `jinko:book-trip` | Book flights, hotels, or both — travelers, ancillaries, and payment | "Book the cheapest flight and pay" |
44
- | `jinko:manage-booking` | Check refund eligibility and process refunds | "Can I get a refund on booking ORD-123?" |
43
+ | `jinko:search-cars` | Search live car-rental offers by pick-up airport, place or coordinates, dates and driver | "Rent a car at Lyon airport from the 25th to the 28th" |
44
+ | `jinko:book-trip` | Book flights, hotels, rental cars, or any mix — travelers, ancillaries, and payment | "Book the cheapest flight and pay" |
45
+ | `jinko:manage-booking` | Refund or exchange flights, cancel hotels and car rentals | "Can I get a refund on booking JNK-A7B3X9?" |
45
46
  | `jinko:account` | Account setup guide — API keys, quotas, dashboard | "How do I set up my Jinko API key?" |
46
- | `jinko:cli` | Run travel ops from the terminal — search flights/hotels, build trips, book, refund, look up bookings via the `jinko` CLI | "Search flights from the terminal with the jinko CLI" |
47
+ | `jinko:cli` | Run travel ops from the terminal — search flights/hotels/cars, build trips, book, refund, cancel, look up bookings via the `jinko` CLI | "Search flights from the terminal with the jinko CLI" |
47
48
 
48
49
  ## Authentication
49
50
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@gojinko/plugin",
3
- "version": "2.28.0",
4
- "description": "Jinko Travel plugin for Claude Code and OpenAI Codex — flight search, booking, and trip management via MCP",
3
+ "version": "2.29.1",
4
+ "description": "Jinko Travel plugin for Claude Code and OpenAI Codex — flight, hotel and car-rental search, booking, and trip management via MCP",
5
5
  "private": false,
6
6
  "license": "MIT",
7
7
  "author": "Jinko <dev@gojinko.com>",
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: book-trip
3
- description: Book a trip end-to-end — flights, hotels, or both in one cart. Live pricing, traveler details, ancillaries, and payment via the Jinko Travel API. Use when the user wants to book, price-check, or pay for travel.
3
+ description: Book a trip end-to-end — flights, hotels, rental cars, or any mix in one cart. Live pricing, traveler details, ancillaries, and payment via the Jinko Travel API. Use when the user wants to book, price-check, or pay for travel.
4
4
  ---
5
5
 
6
6
  # Book a Trip
@@ -10,10 +10,10 @@ Complete booking flow using Jinko MCP tools. Each step depends on the previous
10
10
  ## Booking Flow
11
11
 
12
12
  ```
13
- flight_search and/or hotel_search → trip (add_item) → trip (upsert_travelers) → [trip (select_ancillaries)] → book
13
+ flight_search and/or hotel_search and/or car_search → trip (add_item) → trip (upsert_travelers) → [trip (select_ancillaries)] → book
14
14
  ```
15
15
 
16
- **Multi-domain carts:** Flights (`trip_item_token` from `flight_search`) and hotels (`htl_*` offer_id from `hotel_search`) can be added to the same trip. One cart, one Stripe checkout. See the `search-hotels` skill for hotel search details.
16
+ **Multi-domain carts:** Flights (`trip_item_token` from `flight_search`), hotels (`htl_*` offer_id from `hotel_search`) and rental cars (`car_*` offer_id from `car_search`) can be added to the same trip. One cart, one Stripe checkout. See the `search-hotels` and `search-cars` skills for those searches. A cart that holds a car needs `contact.title` (step 3) before checkout.
17
17
 
18
18
  ## Step 1: Get live pricing — `flight_search`
19
19
 
@@ -139,7 +139,7 @@ Returns `trip_id`. Save it for all subsequent steps.
139
139
  - `passenger_type`: `"ADULT"` (12+), `"CHILD"` (2-11), `"INFANT"` (under 2) (required)
140
140
  - `nationality`, `passport_number`, `passport_expiry`, `passport_country`: optional
141
141
 
142
- **Contact:** `email` is required, `phone` is optional.
142
+ **Contact:** `email` and `phone` are required. `title` is the booking contact's honorific (`"mr"`, `"ms"`, `"mx"`, …) — **required when the cart holds a car rental**, optional otherwise; the readiness gate refuses a car cart without it before any card is charged. Free text, matched downstream against the rental provider's own title vocabulary, so keep to the common forms.
143
143
 
144
144
  ## Step 4 (optional): Add ancillaries — `trip` with `select_ancillaries`
145
145
 
@@ -194,5 +194,6 @@ Once fulfillment has been scheduled the response carries a top-level `booking_re
194
194
  - **Never skip steps** — each depends on the previous
195
195
  - **Never fabricate traveler data** — always ask the user
196
196
  - **If flight_search returns "flight_unavailable"** — do NOT proceed, show alternatives
197
+ - **A car rental needs `contact.title`** — set it in step 3 or checkout refuses the cart
197
198
  - **Sessions expire** — if you get a 404, start over
198
199
  - **Rate limit**: 1000 requests/30 days per API key
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: jinko-cli
3
- description: Use the `jinko` CLI (npm `@gojinko/cli`) to search flights and hotels, build trips, book, refund, and look up bookings from the terminal. Use when the user wants to run travel operations in a shell, script, CI, or agent loop — or explicitly asks for the "jinko CLI", "jinko command", or running something as a command-line.
3
+ description: Use the `jinko` CLI (npm `@gojinko/cli`) to search flights, hotels and rental cars, build trips, book, refund, cancel, and look up bookings from the terminal. Use when the user wants to run travel operations in a shell, script, CI, or agent loop — or explicitly asks for the "jinko CLI", "jinko command", or running something as a command-line.
4
4
  ---
5
5
 
6
6
  # Jinko CLI
@@ -48,13 +48,15 @@ Prod and sandbox keys are stored separately in `~/.jinko/config.yaml`. Precedenc
48
48
  | `flight-search` | Live pricing — direct search by route + dates, or `--offer-token` price-check (returns bookable `trip_item_token`). Full shop filter set: `--max-stops`, `--departure-time-range`, `--connection-time-*-minutes`, `--refundable-only`, `--checked-bag-included`, `--via-airports`, `--origin-alternate-airports`, … |
49
49
  | `hotel-search` | Live hotel search by city/query/geo/hotel-ids |
50
50
  | `hotel-details` | Rich metadata (gallery, facilities, policies, per-room details) for a single hotel |
51
- | `trip` | Create / update a trip: add items, remove items, set travelers + contact |
51
+ | `car-search` | Live car-rental offers — pick-up by `--pick-up-airport` / `--pick-up-place` / `--pick-up-geo lat,lng,range` (exactly one), branch-local `--pick-up-date-time` / `--drop-off-date-time` (no timezone), `--driver-age`, `--residence-country`. Each offer's `offer_id` (`car_*`) is the `trip_item_token`. |
52
+ | `trip` | Create / update a trip: add items, remove items, set travelers + contact (a car rental needs `contact.title`, the honorific) |
52
53
  | `select-ancillaries` | Add baggage / seats / meals to a trip item |
53
54
  | `checkout` | Finalize a trip → returns `checkout_url` (human pays in browser) + `agent_spt_params` (agent pays programmatically). `book` is a deprecated alias. |
54
55
  | `agent-pay submit` | Pay programmatically with a Shared Payment Token (`--trip-id` + `--token`); returns the Jinko `booking_ref` once authorized; 3DS step-up falls back to `checkout_url` |
55
- | `trip-status` | Full status: cart, quote, fulfillment, bookings, and the Jinko `booking_ref` once fulfillment has been scheduled — it can be present before payment completes, so read `fulfillment.status` for paid (the `--booking-ref` for `get-booking` / `hotel-cancel` / `refund`) |
56
+ | `trip-status` | Full status: cart, quote, fulfillment, bookings, and the Jinko `booking_ref` once fulfillment has been scheduled — it can be present before payment completes, so read `fulfillment.status` for paid (the `--booking-ref` for `get-booking` / `hotel-cancel` / `car-cancel` / `refund`) |
56
57
  | `get-booking` | Retrieve a booking by `JNK-*` ref + last name (guest access). Carries `calendar` — the `.ics` files for the booking's flights and stays; `--format json` carries their contents. |
57
58
  | `refund check / commit / status` | Voluntary refund flow |
59
+ | `car-cancel preview / commit / status` | Car-rental cancellation: `preview` quotes the fee and mints the `cancellation_id` the commit is bound to; `commit` cancels (`--manual-ok` hands a `manual_required` quote to a Jinko agent, only with the customer's consent); `status` re-reads the latest attempt. No `car-exchange` exists — modifying a rental is not offered. |
58
60
  | `schema <command>` | Print request/response schema for a command |
59
61
  | `config` | Read/write CLI config |
60
62
 
@@ -109,6 +111,33 @@ jinko trip --trip-item-token "htl_xxx:rate_yyy"
109
111
  # Mixed carts work: add both flight and hotel items to the same trip_id → single Stripe checkout
110
112
  ```
111
113
 
114
+ ## Car rental flow
115
+
116
+ ```bash
117
+ # Search — times are BRANCH-LOCAL with no timezone; driver age + residence change the price (ask, never guess)
118
+ jinko car-search --pick-up-airport LYS --pick-up-date-time 2026-10-25T10:00:00 \
119
+ --drop-off-date-time 2026-10-28T10:00:00 --driver-age 30 --residence-country FR --currency EUR
120
+ # One-way: give the drop-off its own place
121
+ jinko car-search --pick-up-airport LYS --pick-up-date-time 2026-10-25T10:00:00 \
122
+ --drop-off-airport CDG --drop-off-date-time 2026-10-28T10:00:00 --driver-age 30 --residence-country FR
123
+ # An ambiguous --pick-up-place answers with `candidates` instead of offers: show them and retry with one
124
+ jinko car-search --pick-up-place "Lyon Part-Dieu" …
125
+
126
+ # Book: the offer_id (car_*) is the trip item token; a car cart needs the contact's honorific (title)
127
+ jinko trip --trip-item-token car_9f3b2a17c4e8d501 \
128
+ --travelers '[{"first_name":"Jane","last_name":"Doe","passenger_type":"ADULT"}]' \
129
+ --contact '{"email":"jane@example.com","phone":"+33612345678","title":"ms"}'
130
+ jinko checkout --trip-id tr_ABC
131
+
132
+ # Cancel: preview first (quotes the fee, mints the cancellation_id), confirm with the user, then commit
133
+ jinko get-booking --booking-ref JNK-A7B3X9 --last-name Doe # find the car item_id
134
+ jinko car-cancel preview --booking-ref JNK-A7B3X9 --item-id 42 --last-name Doe
135
+ jinko car-cancel commit --booking-ref JNK-A7B3X9 --item-id 42 --last-name Doe --cancellation-id ccl_…
136
+ jinko car-cancel status --booking-ref JNK-A7B3X9 --item-id 42 --last-name Doe
137
+ ```
138
+
139
+ Reading a car search result: `price.pay_now` is the ONLY amount Jinko charges (`due_at_desk` is paid at the counter, `deposit` is a card hold — never sum them); `package.supplier_name` is the rental company the customer collects from; an EMPTY `cancellation_fees` list means the fee is UNKNOWN, never "free cancellation". On a cancel preview, `fee_known: false` means the same, and `manual_required: true` means a person has to complete it — `car-cancel commit --manual-ok` hands it to a Jinko agent, only once the customer has agreed. Changing a rental (dates, vehicle, extras) is not available: the options are keeping the booking or cancelling it and searching again.
140
+
112
141
  ## Multi-item / mixed carts
113
142
 
114
143
  `jinko trip --trip-id <existing>` reuses the existing cart. Flight + hotel in one cart ships as ONE Stripe checkout.
@@ -134,12 +163,12 @@ jinko trip --trip-id tr_ABC --remove-item-id it_123 --trip-item-token "offer_new
134
163
 
135
164
  ```bash
136
165
  # Retrieve a booking (guest access — no auth needed beyond ref + last name)
137
- jinko get-booking --ref JNK-A7B3X9 --last-name Doe
166
+ jinko get-booking --booking-ref JNK-A7B3X9 --last-name Doe
138
167
 
139
168
  # Refund
140
- jinko refund check --ref JNK-A7B3X9 --last-name Doe
141
- jinko refund commit --ref JNK-A7B3X9 --last-name Doe
142
- jinko refund status --ref JNK-A7B3X9 --last-name Doe
169
+ jinko refund check --item-id 42 --booking-ref JNK-A7B3X9 --last-name Doe
170
+ jinko refund commit --item-id 42 --booking-ref JNK-A7B3X9 --last-name Doe
171
+ jinko refund status --item-id 42 --booking-ref JNK-A7B3X9 --last-name Doe
143
172
  ```
144
173
 
145
174
  ## Output tips
@@ -154,12 +183,17 @@ jinko refund status --ref JNK-A7B3X9 --last-name Doe
154
183
  - **IATA codes**: `--origin PAR` uses a CITY code (matches CDG + ORY + BVA); `--origin CDG` uses an airport. `flight-search` has `--origin-type city|airport` to disambiguate — omit it and the platform classifies the code itself, which is the safest choice.
155
184
  - **Filters are requests, not guarantees**: `flight-search` answers with `applied_filters` and `unapplied_filters` (name + reason). An unapplied filter still returns 200 with offers — post-filter them yourself or tell the user the constraint could not be met. `--format table` prints the report under the results.
156
185
  - **Alternate airports widen an AIRPORT anchor**: `--origin-alternate-airports EWR LGA` adds airports beside `--origin`, never removes results, and the anchor decides ranking — so put the airport that matters most in `--origin`. Against a city anchor the list is ignored and comes back in `unapplied_filters` as `origin` / `destination`.
157
- - **trip_item_token format**: `offer_xxx:fare_yyy` (flight) or `htl_xxx:rate_yyy` (hotel). Always the offer ID + fare/rate ID joined by colon.
158
- - **Token expiry**: offers cached ~30 min. If `checkout` returns a quote failure, re-run `flight-search`/`hotel-search` to get a fresh token.
186
+ - **trip_item_token format**: `offer_xxx:fare_yyy` (flight), `htl_xxx:rate_yyy` (hotel), a raw connection id (ground) or `car_xxx` (car rental) — pass every token verbatim, never truncated.
187
+ - **Token expiry**: offers cached ~30 min (a car offer carries its own `expires_at`). If `checkout` returns a quote failure, re-run `flight-search` / `hotel-search` / `car-search` to get a fresh token.
188
+ - **Car date-times carry no timezone**: `2026-10-25T10:00:00` is the rental desk's own local time. A `Z` or an offset is rejected rather than silently shifting the pick-up.
159
189
  - **Script use**: set `JINKO_API_KEY` env var and use `--format json` so output parses cleanly.
160
190
 
161
191
  ## See also
162
192
 
163
- - MCP-tool equivalents: sibling skills `search-flights`, `search-hotels`, `book-trip`, `manage-booking`
193
+ - MCP-tool equivalents: sibling skills `search-flights`, `search-hotels`, `search-cars`, `book-trip`, `manage-booking`
164
194
  - API docs: `https://docs.gojinko.com`
165
195
  - Source: `packages/cli/src/commands/` in the `jinko-dev-tools` repo
196
+
197
+ ## Servicing a selected booked item
198
+
199
+ Run `get-booking --booking-ref <ref>` first (guests add `--last-name`). Select the intended `items[].item_id` and inspect its `servicing` eligibility. Pass `--booking-ref` and the same `--item-id` to refund, exchange, hotel-cancel and car-cancel actions, including status polls. The ID remains stable after an exchange. Owning credentials may omit the surname; guests supply it. When a 409 `item_selection_required` lists several items, choose one from `items[]` before retrying.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: manage-booking
3
- description: Look up bookings and manage post-booking operations (refunds, cancellations) via the Jinko Travel API. Use when the user asks about booking status, refunds, cancellations, or booking modifications.
3
+ description: Look up bookings and manage post-booking operations (flight refunds and exchanges, hotel and car-rental cancellations) via the Jinko Travel API. Use when the user asks about booking status, refunds, cancellations, or booking modifications.
4
4
  ---
5
5
 
6
6
  # Manage Booking
@@ -25,16 +25,13 @@ Use `get_booking` to retrieve a booking by its Jinko reference and the traveler'
25
25
  - `status`: current booking status (completed, processing, etc.)
26
26
  - `customer_contact`: contact info on the booking
27
27
  - `travelers`: list of travelers
28
- - `items`: booked items with domain (flight/hotel), status, and confirmation details (PNR, confirmation number)
28
+ - `items`: booked items with stable `item_id`, domain, status, per-item `servicing` eligibility and safe confirmation details (airline locator, hotel confirmation number)
29
29
 
30
30
  ## Auth model
31
31
 
32
- `flight_refund` supports two auth modes — pick exactly one per call:
32
+ Call `get_booking` first and choose the booked product from `items[]`. Its numeric `item_id` remains stable after an exchange. Inspect that item's `servicing.can_refund`, `can_void`, `can_exchange`, support levels and refusal reasons before proceeding.
33
33
 
34
- - **Guest auth** (default for end-users): `booking_ref` + `last_name`. Works without any DevPlatform credential — the server resolves the booking via `/bookings/get`.
35
- - **Authenticated** (DevPlatform OAuth / `jnk_*` API keys): `order_id`. Skips the guest resolver.
36
-
37
- Do NOT mix the two modes in one call. The BFF rejects mixed combinations up front.
34
+ Every refund, exchange, hotel cancellation and car-rental cancellation takes `booking_ref` plus the selected `item_id`. Guests also supply `last_name`; a credential that owns the booking may omit it. If `item_id` is omitted and several items match the requested domain, a 409 `item_selection_required` returns safe `items[]`: choose one and repeat with its ID. Carry the same selection through checks, commits and status polls.
38
35
 
39
36
  ## Refund Flow — 3 actions: `check | commit | status`
40
37
 
@@ -46,6 +43,7 @@ Always check eligibility first, then confirm with the user before committing. Us
46
43
  {
47
44
  "action": "check",
48
45
  "booking_ref": "JNK-ZNBGTP",
46
+ "item_id": 42,
49
47
  "last_name": "Doe"
50
48
  }
51
49
  ```
@@ -54,7 +52,7 @@ Always check eligibility first, then confirm with the user before committing. Us
54
52
 
55
53
  - `is_refundable`: whether a refund is possible
56
54
  - `is_automatable`: whether the refund can be processed automatically (vs. manual CS)
57
- - `support_level`: `"automatic"` | `"manual"` | `"unsupported"`
55
+ - `support_level`: `"AUTO"` | `"MANUAL_REQUIRED"` | `"UNSUPPORTED"`
58
56
  - `manual_reason`: explanation if not automatable
59
57
  - `refund_amount`: estimated refund `{ value, currency, decimal_places }`
60
58
  - `penalty_amount`: cancellation fee if applicable
@@ -72,6 +70,7 @@ Only after the user confirms:
72
70
  {
73
71
  "action": "commit",
74
72
  "booking_ref": "JNK-ZNBGTP",
73
+ "item_id": 42,
75
74
  "last_name": "Doe"
76
75
  }
77
76
  ```
@@ -79,7 +78,7 @@ Only after the user confirms:
79
78
  **Response includes:**
80
79
 
81
80
  - `refund_status`: `"refunded"` | `"processing"` | `"failed"` | ...
82
- - `confirmed_refund_amount`: actual refunded `{ value, currency, decimal_places }` (when available)
81
+ - `refund_amount`: customer refund `{ value, currency, decimal_places }` (when available); `confirmed_refund_amount` is a deprecated supplier figure
83
82
  - `refund_reference`: opaque reference string — persist this to poll with `status`
84
83
  - `warnings`: any post-commit caveats
85
84
 
@@ -91,6 +90,7 @@ If `refund_status` is not a terminal state, follow up with `status`.
91
90
  {
92
91
  "action": "status",
93
92
  "booking_ref": "JNK-ZNBGTP",
93
+ "item_id": 42,
94
94
  "last_name": "Doe",
95
95
  "refund_reference": "<from commit response>"
96
96
  }
@@ -109,9 +109,9 @@ If `refund_status` is not a terminal state, follow up with `status`.
109
109
  | Field | Type | Purpose |
110
110
  |---|---|---|
111
111
  | `action` | `"check"` \| `"commit"` \| `"status"` | Required. Which step of the flow. |
112
- | `booking_ref` | string | Guest auth. Jinko booking reference (e.g. `JNK-ZNBGTP`). |
112
+ | `booking_ref` | string | Required. Jinko booking reference (e.g. `JNK-ZNBGTP`). |
113
113
  | `last_name` | string | Guest auth. Last name of the primary traveler. |
114
- | `order_id` | string | Authenticated auth. DevPlatform order ID. |
114
+ | `item_id` | positive integer | Stable booked item ID from `get_booking`. Required when several products of this domain exist. |
115
115
  | `ticket_numbers` | string[] | Optional. Scope refund to specific tickets. |
116
116
  | `provider` | string | Optional. Override provider hint. |
117
117
  | `refund_reference` | string | For `status` only. Returned by `commit`. |
@@ -126,6 +126,7 @@ Use `flight_exchange` to change flights on an existing booking. Always shop firs
126
126
  {
127
127
  "action": "shop",
128
128
  "booking_ref": "JNK-ZNBGTP",
129
+ "item_id": 42,
129
130
  "last_name": "Doe",
130
131
  "preferred_departure_date": "2026-06-15"
131
132
  }
@@ -133,7 +134,7 @@ Use `flight_exchange` to change flights on an existing booking. Always shop firs
133
134
 
134
135
  **Response includes:**
135
136
 
136
- - `support_level`: `"automatic"` | `"manual"` | `"unsupported"`
137
+ - `support_level`: `"AUTO"` | `"MANUAL_REQUIRED"` | `"UNSUPPORTED"`
137
138
  - `offers`: array of `{ offer_id, description, metadata }` — alternative flights
138
139
  - `warnings`: any caveats to surface to the user
139
140
 
@@ -145,6 +146,7 @@ Use `flight_exchange` to change flights on an existing booking. Always shop firs
145
146
  {
146
147
  "action": "price",
147
148
  "booking_ref": "JNK-ZNBGTP",
149
+ "item_id": 42,
148
150
  "last_name": "Doe",
149
151
  "offer_id": "<from shop response>"
150
152
  }
@@ -171,6 +173,7 @@ Only after the user confirms:
171
173
  {
172
174
  "action": "commit",
173
175
  "booking_ref": "JNK-ZNBGTP",
176
+ "item_id": 42,
174
177
  "last_name": "Doe",
175
178
  "offer_id": "<from shop response>",
176
179
  "session_reference": "<from price response>"
@@ -181,7 +184,7 @@ Only after the user confirms:
181
184
 
182
185
  - `status`: `"CONFIRMED"` | `"PENDING"` | `"PARTIAL_FAILURE"`
183
186
  - `exchange_reference`: opaque reference for status polling
184
- - `new_order_id`: new order ID if exchange created a new booking
187
+ - `airline_locator`: airline record locator for the current itinerary; keep servicing with the same Jinko reference and booked item ID
185
188
  - `new_ticket_numbers`: new ticket numbers issued
186
189
  - `original_ticket_status`: status of the original tickets
187
190
  - `payment_outcome`: final payment action taken
@@ -195,6 +198,7 @@ If `status` is not `CONFIRMED`, follow up with `status`.
195
198
  {
196
199
  "action": "status",
197
200
  "booking_ref": "JNK-ZNBGTP",
201
+ "item_id": 42,
198
202
  "last_name": "Doe"
199
203
  }
200
204
  ```
@@ -211,23 +215,121 @@ If `status` is not `CONFIRMED`, follow up with `status`.
211
215
  | Field | Type | Purpose |
212
216
  |---|---|---|
213
217
  | `action` | `"shop"` \| `"price"` \| `"commit"` \| `"status"` | Required. Which step of the flow. |
214
- | `booking_ref` | string | Guest auth. Jinko booking reference (e.g. `JNK-ZNBGTP`). |
218
+ | `booking_ref` | string | Required. Jinko booking reference (e.g. `JNK-ZNBGTP`). |
215
219
  | `last_name` | string | Guest auth. Last name of the primary traveler. |
216
- | `order_id` | string | Authenticated auth. DevPlatform order ID. |
220
+ | `item_id` | positive integer | Stable booked item ID from `get_booking`. Required when several products of this domain exist. |
217
221
  | `ticket_numbers` | string[] | Optional. Scope exchange to specific tickets. |
218
222
  | `provider` | string | Optional. Override provider hint. |
219
223
  | `offer_id` | string | For `price` and `commit`. Exchange offer from `shop`. |
220
224
  | `session_reference` | string | For `commit` only. Returned by `price`. |
221
225
  | `preferred_departure_date` | string | For `shop` only. Preferred new departure date. |
222
226
 
227
+ ## Car Rental Cancellation — `car_cancel`: `preview | commit | status`
228
+
229
+ Cancel a car rental booked through Jinko and refund the payment less the cancellation fee. The fee in force is quoted first and persisted, so the cancellation is bound to the terms the customer saw. **Changing a rental — dates, vehicle, upgrade, extras — is not available.** If the user asks for a modification, say so plainly: the options are keeping the booking as is, or cancelling it (fee shown first) and booking a new rental with `car_search` (see the `search-cars` skill). There is no `car_exchange` tool.
230
+
231
+ ### Step 1: Quote the fee — `car_cancel` with `action: "preview"`
232
+
233
+ ```json
234
+ {
235
+ "action": "preview",
236
+ "booking_ref": "JNK-8PT9VS",
237
+ "item_id": 42,
238
+ "last_name": "Carrard"
239
+ }
240
+ ```
241
+
242
+ Nothing is cancelled. The result is a top-level `status` (`success` here; `not_found` for a wrong booking_ref + last_name pair, which never says which half was wrong; `item_selection_required` with `items[]` when several cars match) with the quote under `data`. **`data` includes:**
243
+
244
+ - `cancellation_id`: the `ccl_…` reference — **required for `commit`**, it binds the commit to this quote
245
+ - `cancellable`: whether the rental can be cancelled as it stands
246
+ - `fee_known`: **`false` means the fee could NOT be established — UNKNOWN, not free.** `fee` and `refund_amount` are then absent, not zero. Say "we will confirm the cancellation fee".
247
+ - `fee`, `paid`, `refund_amount` (paid minus fee; absent is not zero), `non_refundable`
248
+ - `manual_required`: `true` means this cancellation cannot be completed online (fee unknown, rental changed after payment, fee in another currency or above the rental) — `refund_review_reason` says which, and no refund figure may be quoted. See "when a person has to complete it".
249
+ - `refund_pending_review` + `refund_review_reason`: the refund needs a person before it is issued
250
+ - `expires_at`: the quote is committable until then; preview again after it
251
+
252
+ **Present the fee and the refund clearly and get explicit confirmation before committing.** This ends the rental.
253
+
254
+ ### Step 2: Cancel — `car_cancel` with `action: "commit"`
255
+
256
+ Only after the user confirms:
257
+
258
+ ```json
259
+ {
260
+ "action": "commit",
261
+ "booking_ref": "JNK-8PT9VS",
262
+ "item_id": 42,
263
+ "last_name": "Carrard",
264
+ "cancellation_id": "ccl_2f7c9a4e8b1d4c6f9e3a5b7d1c2e4f6a",
265
+ "reason": "Change of plans"
266
+ }
267
+ ```
268
+
269
+ Safe to repeat: a committed cancellation is reported as it stands rather than cancelled twice. On `status: "success"`, **`data` includes:**
270
+
271
+ - `state`: `confirmed` (cancelled, refund issued or on its way) · `pending` (recorded but not finished — the platform or a Jinko agent still has it; follow with `status`, do not commit again) · `rejected` (the supplier declined, the booking still stands — surface `rejected_reason`; an outcome, not an error) · `failed` (read `status` before trying again)
272
+ - `fee_known`, `fee`, `paid`, `refund_amount`
273
+ - `refund_pending_review`: `true` means the booking IS cancelled (or recorded for an agent) but the refund needs a person — do not quote `refund_amount` as final
274
+ - `completed_at`
275
+
276
+ **A commit can be refused without anything happening.** The refusal is the result's top-level `status`, with the platform's own code in `conflict_code`: `quote_expired` (preview again) · `quote_drift` (the refund moved since the preview — `requote` is a fresh `ccl_…` reference and `current_refund` the figure now; show it, then commit with `cancellation_id: <requote>`) · `not_allowed` (the rental can no longer be cancelled as it stands — `error` says why; `action: "status"` reports what stands) · `conflict` with `conflict_code: "active_operation_exists"` (`active_operation` names the cancellation already running — wait, then poll `status`) or `conflict_code: "funds_unavailable"` (`shortfall` is what the original payment cannot cover yet) · `manual_required` (see below). None of these means the booking reference or last name is wrong — that answers `status: "not_found"`.
277
+
278
+ ### When a person has to complete it — `manual_ok`
279
+
280
+ A preview with `cancellable: false` and `manual_required: true` is not a dead end. If — and only if — the customer explicitly agrees to hand the cancellation to a Jinko agent, commit with the same `cancellation_id` and `manual_ok: true`:
281
+
282
+ ```json
283
+ {
284
+ "action": "commit",
285
+ "booking_ref": "JNK-8PT9VS",
286
+ "item_id": 42,
287
+ "last_name": "Carrard",
288
+ "cancellation_id": "ccl_2f7c9a4e8b1d4c6f9e3a5b7d1c2e4f6a",
289
+ "manual_ok": true
290
+ }
291
+ ```
292
+
293
+ The cancellation is then recorded for the agent (`state: "pending"`, `refund_pending_review: true`); nothing is sent to the rental company by that call, and the 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. On a preview that can be committed online it changes nothing.
294
+
295
+ ### Step 3: Poll — `car_cancel` with `action: "status"`
296
+
297
+ ```json
298
+ {
299
+ "action": "status",
300
+ "booking_ref": "JNK-8PT9VS",
301
+ "item_id": 42,
302
+ "last_name": "Carrard"
303
+ }
304
+ ```
305
+
306
+ Read-only; polling can never start a cancellation. A booking with no cancellation on record answers `status: "no_attempt"` — run `preview` first.
307
+
308
+ ### Car Cancel Schema
309
+
310
+ | Field | Type | Purpose |
311
+ |---|---|---|
312
+ | `action` | `"preview"` \| `"commit"` \| `"status"` | Required. Which step of the flow. |
313
+ | `booking_ref` | string | Required. Jinko booking reference (e.g. `JNK-8PT9VS`). |
314
+ | `item_id` | positive integer | Stable booked item ID from `get_booking`. Required when several cars are on the booking. |
315
+ | `last_name` | string | Guest auth — the driver's surname. An owning credential may omit it. |
316
+ | `cancellation_id` | string | For `commit`. The `ccl_…` reference from `preview`. |
317
+ | `reason` | string | For `commit` only. Optional free text, carried into the cancellation email. |
318
+ | `manual_ok` | boolean | For `commit` only. `true` hands a `manual_required` preview to a Jinko agent — only with the customer's explicit agreement. |
319
+
320
+ Money on every step is `{ value, currency, decimal_places, display? }` in minor units — divide by `10^decimal_places`, or print `display`.
321
+
223
322
  ## Important rules
224
323
 
225
324
  - **Always shop before pricing** — never skip the alternatives search.
226
325
  - **Always price before committing** — never skip the pricing step.
227
326
  - **Get user confirmation** — show fare difference, penalties, and payment outcome before committing.
228
- - **Pick one auth mode** — never send both `order_id` and `booking_ref` in the same call.
327
+ - **Keep the selected item** — use the same `booking_ref` and stable `item_id` throughout servicing, including after an exchange.
229
328
  - **Poll with `status`** when `commit` returns a non-terminal status.
230
329
  - **Always check before committing refunds** — never skip the eligibility check.
231
330
  - **Get user confirmation for refunds** — show refund amount and penalty before processing.
232
331
  - **Non-refundable bookings** — if `is_refundable` is false, inform the user and do not attempt commit.
233
332
  - **Poll refund with `status`** when `commit` returns a non-terminal `refund_status`.
333
+ - **Always preview before committing a car cancellation** — the `cancellation_id` binds the commit to the quoted fee, and the preview is where the customer sees the fee.
334
+ - **An unknown car cancellation fee is not a free one** — `fee_known: false` or an absent fee means "we will confirm the fee", never "free".
335
+ - **Car rentals cannot be modified** — never promise a date change, an upgrade or a different vehicle; offer cancel-and-rebook, and send `manual_ok` only with the customer's explicit consent.
@@ -0,0 +1,106 @@
1
+ ---
2
+ name: search-cars
3
+ description: Search live car-rental availability by pick-up airport, place or coordinates, a date-time window and the driver's age and residence, using the Jinko Travel API. Use when the user wants to rent or hire a car, compare rental offers, or book a car.
4
+ ---
5
+
6
+ # Car Rental Search
7
+
8
+ Search live car-rental inventory with the `car_search` Jinko MCP tool. Returns priced, bookable offers whose `offer_id` (`car_*`) is a trip item token — booking rides the shared cart, exactly like a flight or a hotel. There is **no car-specific booking tool**, and there is **no car exchange**: changing a rental's dates, vehicle or extras is not available — the options are keeping the booking or cancelling it (`car_cancel`, in the `manage-booking` skill) and searching again.
9
+
10
+ ## car_search
11
+
12
+ Live search — each call reaches the rental supplier.
13
+
14
+ **Required params:**
15
+
16
+ - `pick_up`: where and when the car is collected
17
+ - `date_time`: **branch-local, zone-less** `"YYYY-MM-DDTHH:MM:SS"` (e.g. `"2026-10-25T10:00:00"`). A `Z` or a UTC offset is rejected — the rental desk works in its own local time.
18
+ - **exactly one** place shape:
19
+ - `airport_code`: 3-letter IATA (e.g. `"LYS"`). Prefer it whenever the user named an airport — it needs no resolution step.
20
+ - `place`: free text (`"lyon part dieu"`, `"Lyon city centre"`), resolved server-side. When it matches several genuinely different rental locations the response carries `candidates` **instead of** offers.
21
+ - `geo`: `{ latitude, longitude, range }` for "near me" (range in metres, minimum 50). **Round-trip only.**
22
+ - A drop-off time, one of:
23
+ - `drop_off_date_time`: branch-local return time — round trip, the car goes back to the pick-up branch.
24
+ - `drop_off`: `{ date_time, airport_code | place | geo }` — a **one-way** rental returned somewhere else.
25
+ - `driver_age`: 18–99. **Price-affecting — ask the user, never guess.**
26
+ - `residence_country`: ISO 3166-1 alpha-2 (e.g. `"FR"`). **Price-affecting**, and decides which suppliers will rent at all.
27
+
28
+ **Optional params:**
29
+
30
+ - `currency`: ISO 4217 display currency (default USD)
31
+ - `lang`: BCP-47 tag for provider text (package names, fuel policy), e.g. `"en-gb"`
32
+
33
+ Provider ids (location, city, branch, supplier) are never accepted on this surface.
34
+
35
+ **Examples:**
36
+
37
+ Round trip from an airport:
38
+ ```json
39
+ {
40
+ "pick_up": { "airport_code": "LYS", "date_time": "2026-10-25T10:00:00" },
41
+ "drop_off_date_time": "2026-10-28T10:00:00",
42
+ "driver_age": 30,
43
+ "residence_country": "FR",
44
+ "currency": "EUR"
45
+ }
46
+ ```
47
+
48
+ One-way, free-text pick-up:
49
+ ```json
50
+ {
51
+ "pick_up": { "place": "Lyon Part-Dieu", "date_time": "2026-10-25T10:00:00" },
52
+ "drop_off": { "airport_code": "CDG", "date_time": "2026-10-28T18:00:00" },
53
+ "driver_age": 42,
54
+ "residence_country": "GB"
55
+ }
56
+ ```
57
+
58
+ **Response:** a top-level `status` — `success`, `ambiguous_place` (candidates instead of offers, see below), `no_results` or `error` — with the result under `data`. `data.offers[]` flattens one vehicle × rate package × branch pair per entry:
59
+
60
+ - `offer_id`: the `car_*` trip item token — pass it **verbatim** to `trip(add_item)`
61
+ - `expires_at`: about 30 minutes — search again after it
62
+ - `on_request`: the supplier confirms by hand, so the booking settles asynchronously
63
+ - `vehicle`: `name` (the model, "or similar" unless `model_guaranteed`), `acriss_code`, `category`, `transmission`, `fuel_type`, `seats`, `doors`, suitcase counts, `air_conditioned`, `images[]`
64
+ - `package`: `name` (the rate plan), **`supplier_name` (the rental company the customer physically collects the car from — Avis, Hertz, Europcar, Sixt — show it with every offer)**, `fuel_policy`, `mileage_unlimited` / `mileage_allowance`, `inclusions`, `coverages`, `fees`
65
+ - `pick_up` / `drop_off`: the branch — `name`, `address`, `city`, `country`, `phone`, `date_time` (branch-local), `time_zone` (IANA — the only way to turn a local time into an instant), `opening_hours`, `out_of_hours`, `requires_flight_number`, `terminals`, `is_meet_and_greet`
66
+ - `price`: see money below
67
+ - `cancellation_fees[]`: `{ type, fee, non_refundable, applicable_from, applicable_to, applicable_now }`
68
+ - `driver_age_range`: `{ min, max }`
69
+
70
+ Plus `data.resolved_place` (what an unambiguous free-text place matched), `data.currency`, `data.warnings`, and the truncation counters `data.total_found` / `data.offers_shown` / `data.offers_omitted`: when `offers_omitted` is above zero, `data.notice` says so — **narrow the search** (dates, place, a smaller radius) rather than treating the list as complete; there is no paging.
71
+
72
+ ### Ambiguous place — `candidates`
73
+
74
+ When `place` is ambiguous the response is `status: "ambiguous_place"` with `data.candidates[]` (`{ name, kind, city, country }`) and **no offers**. That is a retry signal, not an empty result: put the candidates to the user and search again with the chosen candidate's `name` as `place` (qualify it with the city — "City Centre, Lyon" — when two share a name). **Never auto-pick a candidate**: "Lyon" is an airport, a rail station and a downtown office that book three different counters.
75
+
76
+ ## Reading the money
77
+
78
+ - `price.pay_now` is the **only** amount Jinko charges at checkout.
79
+ - `price.due_at_desk` is collected by the rental desk in local currency — display only.
80
+ - `price.deposit` is a card hold; `price.estimated_total` is the supplier's FX-movable estimate.
81
+ - **Never sum them into a total.**
82
+ - Amounts are `{ value, currency, decimal_places, display? }` — `value` is an integer in minor units; divide by `10^decimal_places`, or print `display` as sent.
83
+ - **An empty `cancellation_fees` list means the supplier published no schedule: the fee is UNKNOWN. Never present that as free cancellation.** A coverage's `excess` of `null` means "not stated", not "no excess".
84
+
85
+ ## Booking flow
86
+
87
+ Cars use the same cart as flights and hotels:
88
+
89
+ ```
90
+ car_search → trip(add_item, trip_item_token=<car_* offer_id>) → trip(upsert_travelers, contact.title!) → book
91
+ ```
92
+
93
+ Two things differ from a flight or hotel booking:
94
+
95
+ - **`contact.title` is required.** The booking contact's honorific (`"mr"`, `"ms"`, `"mx"`, …) goes in `upsert_travelers.contact.title`. The readiness gate refuses a car cart without it, before any card is charged. It is matched against the rental provider's own title vocabulary, so keep to the common forms.
96
+ - **`driver_age` is baked into the rate** and is never asked again at booking.
97
+
98
+ See the `book-trip` skill for steps 2–5; they are otherwise identical. To cancel a booked rental, use `car_cancel` in the `manage-booking` skill.
99
+
100
+ ## Important notes
101
+
102
+ - **Date-times**: `YYYY-MM-DDTHH:MM:SS`, branch-local, no timezone; drop-off must be after pick-up.
103
+ - **Places**: exactly one of `airport_code`, `place`, `geo` per end; `geo` is round-trip only.
104
+ - **Offers expire** (`expires_at`): if `trip(add_item)` fails, search again.
105
+ - **`requires_flight_number` on a branch** is the supplier's policy and cannot be satisfied today (Jinko carries no flight number): `"always"` means that branch cannot be booked at all — prefer an offer from another branch.
106
+ - **No modifications.** Do not promise a date change, an upgrade or a different vehicle on an existing rental; offer to cancel (fee shown first) and book again.