curl --request POST \
--url https://api.example.com/v1/car_exchange_preview \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-8PT9VS",
"last_name": "Carrard",
"pick_up_date_time": "2026-09-13T10:00:00",
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1
}
]
}
'import requests
url = "https://api.example.com/v1/car_exchange_preview"
payload = {
"booking_ref": "JNK-8PT9VS",
"last_name": "Carrard",
"pick_up_date_time": "2026-09-13T10:00:00",
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1
}
]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
booking_ref: 'JNK-8PT9VS',
last_name: 'Carrard',
pick_up_date_time: '2026-09-13T10:00:00',
ancillaries: [{offer_id: 'CHILD_SEAT', quantity: 1}]
})
};
fetch('https://api.example.com/v1/car_exchange_preview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/car_exchange_preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'booking_ref' => 'JNK-8PT9VS',
'last_name' => 'Carrard',
'pick_up_date_time' => '2026-09-13T10:00:00',
'ancillaries' => [
[
'offer_id' => 'CHILD_SEAT',
'quantity' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/car_exchange_preview"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/v1/car_exchange_preview")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/car_exchange_preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"exchange_id": "exc_7c1e4b9a2d8f4e6b9a3c5d7e1f2a4b6c",
"exchangeable": true,
"reason": "<string>",
"current": {
"vehicle": {
"name": "Peugeot 308 or similar",
"category": "compact",
"acriss_code": "CDMR"
},
"pick_up": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"drop_off": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1,
"label": "Child seat",
"paid_at": "now",
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
]
},
"paid": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
},
"offers": [
{
"exchange_offer_token": "cxo_3f9a1c7e5b2d4a8c6e1f3b5d7a9c2e4f",
"rental": {
"vehicle": {
"name": "Peugeot 308 or similar",
"category": "compact",
"acriss_code": "CDMR"
},
"pick_up": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"drop_off": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1,
"label": "Child seat",
"paid_at": "now",
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
]
},
"on_request": true,
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
},
"delta": {
"direction": "add_collect",
"amount": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
}
],
"warnings": [
"<string>"
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "Malformed JSON in request body.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/api-reference/authentication"
}
}{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "booking not found"
}
}{
"error": {
"code": "CONFLICT",
"message": "an exchange is already in progress for this booking",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "origins: origins is required; trip_type: trip_type is required",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit or quota exceeded.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "sabre-rest BargainFinderMaxRQ failed with status 400: 27131 - Number of connection locations exceeds maximum allowed",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_UNAVAILABLE",
"message": "All flight providers are temporarily unable to serve this search. Please retry later. Provider reasons: sabre-rest: provider temporarily closed; travelfusion: quota exhausted",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "sabre-rest BargainFinderMaxRQ timed out after 30s",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}car-exchange-preview
Preview the rentals a car booking could be exchanged to
curl --request POST \
--url https://api.example.com/v1/car_exchange_preview \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-8PT9VS",
"last_name": "Carrard",
"pick_up_date_time": "2026-09-13T10:00:00",
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1
}
]
}
'import requests
url = "https://api.example.com/v1/car_exchange_preview"
payload = {
"booking_ref": "JNK-8PT9VS",
"last_name": "Carrard",
"pick_up_date_time": "2026-09-13T10:00:00",
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1
}
]
}
headers = {
"X-API-Key": "<api-key>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'X-API-Key': '<api-key>', 'Content-Type': 'application/json'},
body: JSON.stringify({
booking_ref: 'JNK-8PT9VS',
last_name: 'Carrard',
pick_up_date_time: '2026-09-13T10:00:00',
ancillaries: [{offer_id: 'CHILD_SEAT', quantity: 1}]
})
};
fetch('https://api.example.com/v1/car_exchange_preview', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/v1/car_exchange_preview",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'booking_ref' => 'JNK-8PT9VS',
'last_name' => 'Carrard',
'pick_up_date_time' => '2026-09-13T10:00:00',
'ancillaries' => [
[
'offer_id' => 'CHILD_SEAT',
'quantity' => 1
]
]
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json",
"X-API-Key: <api-key>"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/v1/car_exchange_preview"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("X-API-Key", "<api-key>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/v1/car_exchange_preview")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/car_exchange_preview")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["X-API-Key"] = '<api-key>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"booking_ref\": \"JNK-8PT9VS\",\n \"last_name\": \"Carrard\",\n \"pick_up_date_time\": \"2026-09-13T10:00:00\",\n \"ancillaries\": [\n {\n \"offer_id\": \"CHILD_SEAT\",\n \"quantity\": 1\n }\n ]\n}"
response = http.request(request)
puts response.read_body{
"exchange_id": "exc_7c1e4b9a2d8f4e6b9a3c5d7e1f2a4b6c",
"exchangeable": true,
"reason": "<string>",
"current": {
"vehicle": {
"name": "Peugeot 308 or similar",
"category": "compact",
"acriss_code": "CDMR"
},
"pick_up": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"drop_off": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1,
"label": "Child seat",
"paid_at": "now",
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
]
},
"paid": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
},
"offers": [
{
"exchange_offer_token": "cxo_3f9a1c7e5b2d4a8c6e1f3b5d7a9c2e4f",
"rental": {
"vehicle": {
"name": "Peugeot 308 or similar",
"category": "compact",
"acriss_code": "CDMR"
},
"pick_up": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"drop_off": {
"branch_name": "Lyon Saint-Exupery Airport",
"city": "Lyon",
"date_time": "2026-09-13T10:00:00"
},
"ancillaries": [
{
"offer_id": "CHILD_SEAT",
"quantity": 1,
"label": "Child seat",
"paid_at": "now",
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
]
},
"on_request": true,
"price": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
},
"delta": {
"direction": "add_collect",
"amount": {
"value": 41250,
"currency": "EUR",
"decimal_places": 2
}
}
}
],
"warnings": [
"<string>"
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "Malformed JSON in request body.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/api-reference/authentication"
}
}{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient balance — this call costs $0.0150 and your organization has $0.0000 available. Top up at https://dashboard.gojinko.com/developers/billing/topup",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "NOT_FOUND",
"message": "booking not found"
}
}{
"error": {
"code": "CONFLICT",
"message": "an exchange is already in progress for this booking",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "origins: origins is required; trip_type: trip_type is required",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit or quota exceeded.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "sabre-rest BargainFinderMaxRQ failed with status 400: 27131 - Number of connection locations exceeds maximum allowed",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_UNAVAILABLE",
"message": "All flight providers are temporarily unable to serve this search. Please retry later. Provider reasons: sabre-rest: provider temporarily closed; travelfusion: quota exhausted",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "sabre-rest BargainFinderMaxRQ timed out after 30s",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}pick_up_date_time / drop_off_date_time (branch-local YYYY-MM-DDTHH:MM:SS; omit either to keep the booked time), and with the rate extras (child seat, GPS, additional driver, excess cover) the rental should end up with (ancillaries; omit to keep what the booking carries, [] to remove every extra), each priced in full with that selection and with its delta against what was paid. Nothing is changed. Vehicle choice is not an input: every alternative at the requested times comes back as its own offer. The returned exchange_id plus one offer’s exchange_offer_token are what car_exchange_commit consumes. A booking that cannot be exchanged (already cancelled, an exchange already in flight) answers 200 with exchangeable: false and a reason, not an error. Guest-authenticated: booking_ref + last_name; a wrong pair returns 404 rather than confirming the booking’s existence.Authorizations
Body
Jinko booking reference from the confirmation email.
1"JNK-8PT9VS"
Lead traveler's last name, exactly as on the booking.
1"Carrard"
Show child attributes
Show child attributes
New pick-up date-time, branch-local, no timezone. Omit to keep the booked time.
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$"2026-09-13T10:00:00"
New drop-off date-time, branch-local, no timezone. Omit to keep the booked time.
^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$"2026-09-16T10:00:00"
The rate extras (child seat, GPS, additional driver, excess cover) the rental should END UP with. Omit to keep what the booking carries today; send [] to remove every extra; send a list to replace the selection. Every offer comes back priced with this selection and echoes it under rental.ancillaries. To change only the extras, send this without new times: the current rental returns as an offer and its delta settles like any other exchange. A paid_at: local extra is selectable but never enters the price.
Show child attributes
Show child attributes
Response
Exchange alternatives with their price deltas
Opaque reference of this preview ("exc_…"). Pass to car_exchange_commit with the chosen offer token — it binds the commit to the prices quoted here. Absent when the booking is not exchangeable. Treat as an opaque string; the format may evolve.
"exc_7c1e4b9a2d8f4e6b9a3c5d7e1f2a4b6c"
true
Why the booking cannot be exchanged (already cancelled, an exchange already in flight). Absent when it can.
A rental: the vehicle, where it is collected and where it is returned. Used for both the booking as it stands today (current on the preview) and the one a candidate would replace it with (rental on an offer).
Show child attributes
Show child attributes
What the customer paid — the basis every delta is computed against. Absent when the booking is not exchangeable.
Show child attributes
Show child attributes
Replacement candidates at the requested times, each priced in full and with its delta. Empty when nothing is available, or when the booking is not exchangeable.
Show child attributes
Show child attributes
