curl --request POST \
--url https://api.gojinko.com/v1/exchange_shop \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_shop"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe"
}
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-A0AUR2', last_name: 'Doe'})
};
fetch('https://api.gojinko.com/v1/exchange_shop', 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.gojinko.com/v1/exchange_shop",
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-A0AUR2',
'last_name' => 'Doe'
]),
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.gojinko.com/v1/exchange_shop"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\"\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.gojinko.com/v1/exchange_shop")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_shop")
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-A0AUR2\",\n \"last_name\": \"Doe\"\n}"
response = http.request(request)
puts response.read_body{
"support_level": "AUTO",
"reason_code": "NOT_EXCHANGEABLE",
"reason": "This booking cannot be exchanged online. Contact Jinko support.",
"offers": [
{
"offer_id": "exch_offer_3c1a9f",
"description": "AA100, 23 Sep, JFK-DFW-SJC",
"estimated_payment_outcome": "additional_payment_due",
"estimated_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"non_refundable_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"validating_carrier": "AA",
"fare_brand_code": "MAINSL",
"fare_brand_name": "MAIN SELECT",
"legs": [
{
"stops": 0,
"duration_minutes": 530,
"segments": [
{
"airline": "AA",
"operating_carrier": "BA",
"flight_number": "6957",
"departure_airport": "MIA",
"departure_time": "2026-11-24T19:35:00",
"arrival_airport": "LHR",
"arrival_time": "2026-11-25T09:05:00",
"duration_minutes": 530,
"cabin_name": "Economy",
"fare_brand_key": "MAINSL",
"fare_basis_code": "OVAIZNB3",
"rbd": "O"
}
]
}
],
"fare_basis_codes": [
"OVAIZNB3"
],
"booking_classes": [
"O"
],
"cabin": "Economy"
}
],
"warnings": [
"<string>"
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/authentication/api-keys"
}
}{
"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": "Resource not found.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "GONE",
"message": "The resource no longer exists.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "A required field is missing or invalid.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "The request was declined for this offer. Try another offer.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_UNAVAILABLE",
"message": "The service is temporarily unavailable. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "The request timed out before a result was available. Retry the request.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}exchange shop
Shop for flight exchange alternatives
curl --request POST \
--url https://api.gojinko.com/v1/exchange_shop \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_shop"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe"
}
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-A0AUR2', last_name: 'Doe'})
};
fetch('https://api.gojinko.com/v1/exchange_shop', 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.gojinko.com/v1/exchange_shop",
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-A0AUR2',
'last_name' => 'Doe'
]),
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.gojinko.com/v1/exchange_shop"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\"\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.gojinko.com/v1/exchange_shop")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_shop")
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-A0AUR2\",\n \"last_name\": \"Doe\"\n}"
response = http.request(request)
puts response.read_body{
"support_level": "AUTO",
"reason_code": "NOT_EXCHANGEABLE",
"reason": "This booking cannot be exchanged online. Contact Jinko support.",
"offers": [
{
"offer_id": "exch_offer_3c1a9f",
"description": "AA100, 23 Sep, JFK-DFW-SJC",
"estimated_payment_outcome": "additional_payment_due",
"estimated_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"non_refundable_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"validating_carrier": "AA",
"fare_brand_code": "MAINSL",
"fare_brand_name": "MAIN SELECT",
"legs": [
{
"stops": 0,
"duration_minutes": 530,
"segments": [
{
"airline": "AA",
"operating_carrier": "BA",
"flight_number": "6957",
"departure_airport": "MIA",
"departure_time": "2026-11-24T19:35:00",
"arrival_airport": "LHR",
"arrival_time": "2026-11-25T09:05:00",
"duration_minutes": 530,
"cabin_name": "Economy",
"fare_brand_key": "MAINSL",
"fare_basis_code": "OVAIZNB3",
"rbd": "O"
}
]
}
],
"fare_basis_codes": [
"OVAIZNB3"
],
"booking_classes": [
"O"
],
"cabin": "Economy"
}
],
"warnings": [
"<string>"
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "AUTH_REQUIRED",
"message": "Invalid or expired API key.",
"doc_url": "https://docs.gojinko.com/authentication/api-keys"
}
}{
"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": "Resource not found.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "GONE",
"message": "The resource no longer exists.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "A required field is missing or invalid.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "RATE_LIMITED",
"message": "Too many requests. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_REJECTED",
"message": "The request was declined for this offer. Try another offer.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_UNAVAILABLE",
"message": "The service is temporarily unavailable. Retry after the Retry-After delay.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}{
"error": {
"code": "UPSTREAM_TIMEOUT",
"message": "The request timed out before a result was available. Retry the request.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
}
}exchange price.
Name each leg to change in segments_to_exchange by its first departure and final arrival airport, as get_booking lists it under items[].confirmation.details.flight.legs; legs you do not name stay as booked. preferred_departure_date moves the first leg to that date and reshops every leg, so use it only for a booking with a single leg.
A selection the booking refuses answers 400 before any supplier is asked: LEG_ALREADY_DEPARTED, DEPARTURE_DATE_IN_PAST, LEG_DATES_OUT_OF_ORDER or INVALID_SEGMENTS_TO_EXCHANGE. error.message lists the booked legs, except for an INVALID_SEGMENTS_TO_EXCHANGE entry that is malformed (a field of the wrong type, or a date not written YYYY-MM-DD). A booking that cannot be exchanged as it stands answers 409 NOT_EXCHANGEABLE. See Errors.Authorizations
Body
Jinko booking reference. Call get_booking first, then select its booked_item_id for servicing.
1"JNK-A0AUR2"
The booked item, from get_booking items[].booked_item_id. Preserved across exchanges. Omit only when the booking has exactly one item of the requested domain; otherwise a 409 returns items to choose from.
^itm_[a-z2-7]+$(?![\s\S])"itm_aaaaaaaaaaaaafhuxsdxpbzrbfz5hm3a"
Required for guest lookup. A credential that owns the booking may omit it; ownership is checked by the platform.
1"Doe"
Deprecated: name the booking with booking_ref and booked_item_id from get_booking. Names the booking instead of booking_ref, never beside it, and needs a credential that owns the booking. Accepted until 2027-04-30; a request that sends it is answered with Deprecation and Sunset headers.
1Deprecated: omit it. The platform uses the supplier recorded with the booking. Accepted until 2027-04-30; a request that sends it is answered with Deprecation and Sunset headers.
Show child attributes
Show child attributes
The legs to change. Each entry is matched to a booked leg by its origin and destination and gives the new departure date. Booked legs you do not list are kept unchanged: every offer is the whole itinerary, with the kept legs as booked. Name each leg by its booked airport codes (type: airport): the first departure and the last arrival airport of that journey, as get_booking lists the leg — not a connection airport. A city code cannot be matched and is refused. An entry that matches no booked leg is refused with 400 INVALID_SEGMENTS_TO_EXCHANGE; a leg that has already departed with 400 LEG_ALREADY_DEPARTED; a date before today at the departure airport with 400 DEPARTURE_DATE_IN_PAST; new dates that would put the legs out of order with 400 LEG_DATES_OUT_OF_ORDER. Each refusal lists the booked legs. Some suppliers cannot keep a leg yet; for those bookings a request that names only some of the legs is refused with 400 PARTIAL_EXCHANGE_UNSUPPORTED — name every leg to reshop the whole itinerary.
1Show child attributes
Show child attributes
Legacy. Moves the FIRST leg of the booking to this date and reshops every leg, so it cannot change only a later leg (a return) and can replace the flights of a leg you meant to keep. Use segments_to_exchange instead.
Response
Shop for flight exchange alternatives
How this action can be carried out. AUTO — the platform completes it end to end through the API. MANUAL_REQUIRED — it is possible, but a Jinko agent has to act; call the API to raise it and expect a delay rather than an immediate result. UNSUPPORTED — the provider or fare does not allow it at all; nothing you send will change that. Do not treat MANUAL_REQUIRED as a failure, and do not retry UNSUPPORTED. On the refund check manual_reason says why it is not AUTO, on the exchange shop reason.
AUTO, MANUAL_REQUIRED, UNSUPPORTED Why the exchange is not automatic, as a Jinko code to route on, never a supplier’s. Present whenever support_level is not AUTO, absent when it is. Today NOT_EXCHANGEABLE with support_level: UNSUPPORTED — the booking cannot be exchanged online — and MANUAL_REQUIRED with support_level: MANUAL_REQUIRED — a Jinko agent has to carry out the exchange.
"NOT_EXCHANGEABLE"
Why the exchange is not automatic, in words the customer can be shown. Present whenever support_level is not AUTO, absent when it is. It is a fixed Jinko sentence and never the supplier’s wording: “This booking cannot be exchanged online. Contact Jinko support.” with NOT_EXCHANGEABLE, “This request needs manual handling by Jinko support.” with MANUAL_REQUIRED.
"This booking cannot be exchanged online. Contact Jinko support."
Show child attributes
Show child attributes
Notes about the booking and its documents, each said once, in words the customer can be shown. A note the supplier sends as free text without a code is left out.
