@gojinko/plugin 2.28.0 → 2.29.0
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.
- package/.claude-plugin/plugin.json +4 -2
- package/.codex-plugin/plugin.json +9 -5
- package/README.md +6 -5
- package/package.json +2 -2
- package/skills/book-trip/SKILL.md +5 -4
- package/skills/cli/SKILL.md +44 -10
- package/skills/manage-booking/SKILL.md +118 -16
- package/skills/search-cars/SKILL.md +106 -0
|
@@ -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
|
|
4
|
-
"version": "2.
|
|
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.0",
|
|
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
|
|
4
|
-
"version": "2.
|
|
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.0",
|
|
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.
|
|
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
|
-
"
|
|
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
|
-
- **
|
|
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:
|
|
44
|
-
| `jinko:
|
|
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.
|
|
4
|
-
"description": "Jinko Travel plugin for Claude Code and OpenAI Codex — flight search, booking, and trip management via MCP",
|
|
3
|
+
"version": "2.29.0",
|
|
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
|
|
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`)
|
|
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`
|
|
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
|
package/skills/cli/SKILL.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: jinko-cli
|
|
3
|
-
description: Use the `jinko` CLI (npm `@gojinko/cli`) to search flights and
|
|
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
|
-
| `
|
|
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
|
|
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)
|
|
158
|
-
- **Token expiry**: offers cached ~30 min. If `checkout` returns a quote failure, re-run `flight-search
|
|
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
|
|
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
|
-
`
|
|
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
|
-
|
|
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`: `"
|
|
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
|
-
- `
|
|
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 |
|
|
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
|
-
| `
|
|
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`: `"
|
|
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
|
-
- `
|
|
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 |
|
|
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
|
-
| `
|
|
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
|
-
- **
|
|
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.
|