curl --request POST \
--url https://api.gojinko.com/v1/exchange_commit \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f",
"quote_id": "exch_7a1c93f0"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_commit"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f",
"quote_id": "exch_7a1c93f0"
}
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',
offer_id: 'exch_offer_3c1a9f',
quote_id: 'exch_7a1c93f0'
})
};
fetch('https://api.gojinko.com/v1/exchange_commit', 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_commit",
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',
'offer_id' => 'exch_offer_3c1a9f',
'quote_id' => 'exch_7a1c93f0'
]),
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_commit"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\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_commit")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_commit")
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 \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\n}"
response = http.request(request)
puts response.read_body{
"airline_locator": "ABC123",
"booking_ref": "JNK-A0AUR2",
"booking_reference": "JNK-A0AUR2",
"new_ticket_numbers": [
"0012345678901"
],
"status": "pending",
"payment_outcome": "ADD_COLLECT",
"checkout_url": "https://app.gojinko.com/checkout?t=eyJyIjoiY2FydCIs…",
"stripe_checkout_session_url": "<string>",
"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": "CONFLICT",
"message": "This exchange can't be refunded automatically, so it has been sent to Jinko support. They will complete it and refund you; there is nothing else to do."
},
"code": "funds_unavailable",
"manual_handling": {
"status": "pending"
}
}{
"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 commit
Commit a flight exchange
curl --request POST \
--url https://api.gojinko.com/v1/exchange_commit \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f",
"quote_id": "exch_7a1c93f0"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_commit"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f",
"quote_id": "exch_7a1c93f0"
}
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',
offer_id: 'exch_offer_3c1a9f',
quote_id: 'exch_7a1c93f0'
})
};
fetch('https://api.gojinko.com/v1/exchange_commit', 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_commit",
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',
'offer_id' => 'exch_offer_3c1a9f',
'quote_id' => 'exch_7a1c93f0'
]),
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_commit"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\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_commit")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_commit")
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 \"offer_id\": \"exch_offer_3c1a9f\",\n \"quote_id\": \"exch_7a1c93f0\"\n}"
response = http.request(request)
puts response.read_body{
"airline_locator": "ABC123",
"booking_ref": "JNK-A0AUR2",
"booking_reference": "JNK-A0AUR2",
"new_ticket_numbers": [
"0012345678901"
],
"status": "pending",
"payment_outcome": "ADD_COLLECT",
"checkout_url": "https://app.gojinko.com/checkout?t=eyJyIjoiY2FydCIs…",
"stripe_checkout_session_url": "<string>",
"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": "CONFLICT",
"message": "This exchange can't be refunded automatically, so it has been sent to Jinko support. They will complete it and refund you; there is nothing else to do."
},
"code": "funds_unavailable",
"manual_handling": {
"status": "pending"
}
}{
"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"
}
}status: "pending"; poll exchange status until it reads confirmed, partial_failure or failed.
When the customer pays the difference
Withpayment_outcome: "ADD_COLLECT" the commit carries checkout_url, the page where the customer pays the difference. Nothing is exchanged until that payment authorizes. Send the customer to the page, then poll exchange_status, which returns the same checkout_url while the payment is outstanding. The page takes the payment for up to one hour, or until the new fare’s own deadline when that comes sooner. Until then a second commit answers 409 with code: "exchange_in_progress" and starts nothing. If the customer has not paid by then, the exchange is cancelled within a minute: exchange_status answers failed with the reason in warnings and no checkout_url, the page no longer works, nothing is charged and the booking is unchanged. The booking can then be exchanged, refunded or cancelled again; a new commit starts a new exchange with a new checkout_url.
When an exchange can’t be refunded automatically
A409 with manual_handling.status: "pending" means the confirmed request is with Jinko support, who will complete it and refund the traveler. Show error.message and do not automatically retry commit. Read get_booking and the item’s servicing.exchange to follow the request through manual handling to completion or closure. Pricing alone does not open the request.
See Flight exchanges for the customer-visible states and support workflow.Authorizations
Body
1Jinko 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 quote_id exchange_price returned. Not required. Optional after a refused exchange price, when committing the same offer to request manual handling.
Response
Commit a flight exchange
Deprecated: read the item’s supplier_references on POST /v1/get_booking, which carries each airline’s record locator with the airline that issued it. Airline record locator for the current itinerary.
"ABC123"
"JNK-A0AUR2"
Deprecated: use booking_ref instead. Same value.
"JNK-A0AUR2"
["0012345678901"]
A commit answers pending: the exchange is carried out after this call, whatever the payment outcome. Follow it with exchange_status until it reads confirmed, partial_failure or failed.
confirmed, pending, partial_failure, failed "pending"
ADD_COLLECT — the customer pays the difference first: send them to checkout_url; the exchange runs only after that payment authorizes. EVEN — nothing to pay. REFUND — the difference goes back to the original payment method once the exchange completes.
EVEN, ADD_COLLECT, REFUND "ADD_COLLECT"
Present when payment_outcome is ADD_COLLECT: the page where the customer pays the difference. Nothing is exchanged until that payment authorizes. exchange_status returns the same page while the exchange waits for it.
"https://app.gojinko.com/checkout?t=eyJyIjoiY2FydCIs…"
Deprecated: use checkout_url instead. The same payment page, under a provider’s name.
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.
