curl --request POST \
--url https://api.gojinko.com/v1/exchange_price \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_price"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f"
}
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'})
};
fetch('https://api.gojinko.com/v1/exchange_price', 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_price",
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'
]),
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_price"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\"\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_price")
.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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_price")
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}"
response = http.request(request)
puts response.read_body{
"payment_outcome": "ADD_COLLECT",
"customer_amounts": {
"original_fare": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"penalty_amount": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_due": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_refund": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"residual_value": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
},
"fare_difference": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"penalty_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"original_fare": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_due": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_refund": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare_details": {
"fare_brand_name": "MAIN CABIN FLEXIBLE",
"fare_brand_code": "MAINFL",
"fare_basis_codes": [
"<string>"
],
"endorsements": "USD281.86 NONREFUNDABLE/NONREF/FAREDIF/CXL BY FLT TIME OR NOVALUE",
"is_refundable": true,
"is_changeable": true,
"refund_policy": "Non-refundable",
"change_policy": "Changeable (conditions apply)",
"checked_baggage": {
"pieces": 123,
"weight": 123,
"weight_unit": "KG",
"dimensions": "<string>",
"description": "1 bag, 23kg included"
},
"carry_on_baggage": {
"pieces": 123,
"weight": 123,
"weight_unit": "KG",
"dimensions": "<string>",
"description": "1 bag, 23kg included"
},
"extra_baggage_options": [
{
"id": "<string>",
"pieces": 123,
"weight": 123,
"weight_unit": "<string>",
"is_included": true,
"price_per_bag": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "<string>",
"segment_id": "<string>",
"journey_id": "<string>"
}
],
"extra_carry_on_options": [
{
"id": "<string>",
"pieces": 123,
"weight": 123,
"weight_unit": "<string>",
"is_included": true,
"price_per_bag": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "<string>",
"segment_id": "<string>",
"journey_id": "<string>"
}
]
},
"fare_change_notice": {
"original_brand": "MAIN SELECT",
"new_brand": "MAIN CABIN",
"refundability_changed": true,
"text": "<string>"
},
"quote_id": "exch_7a1c93f0",
"session_reference": "exch_7a1c93f0",
"expires_at": "2026-06-01T13:04:56Z",
"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 would refund 1050.00 USD, and only 789.00 is still refundable on the original payment. It can't be refunded automatically. Confirming this exchange sends it to Jinko support, who will complete it and refund you."
},
"code": "funds_unavailable"
}{
"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
Price a specific exchange offer
curl --request POST \
--url https://api.gojinko.com/v1/exchange_price \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f"
}
'import requests
url = "https://api.gojinko.com/v1/exchange_price"
payload = {
"booking_ref": "JNK-A0AUR2",
"last_name": "Doe",
"offer_id": "exch_offer_3c1a9f"
}
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'})
};
fetch('https://api.gojinko.com/v1/exchange_price', 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_price",
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'
]),
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_price"
payload := strings.NewReader("{\n \"booking_ref\": \"JNK-A0AUR2\",\n \"last_name\": \"Doe\",\n \"offer_id\": \"exch_offer_3c1a9f\"\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_price")
.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}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.com/v1/exchange_price")
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}"
response = http.request(request)
puts response.read_body{
"payment_outcome": "ADD_COLLECT",
"customer_amounts": {
"original_fare": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"penalty_amount": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_due": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_refund": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"residual_value": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
},
"fare_difference": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"penalty_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"original_fare": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_due": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_refund": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"new_fare_details": {
"fare_brand_name": "MAIN CABIN FLEXIBLE",
"fare_brand_code": "MAINFL",
"fare_basis_codes": [
"<string>"
],
"endorsements": "USD281.86 NONREFUNDABLE/NONREF/FAREDIF/CXL BY FLT TIME OR NOVALUE",
"is_refundable": true,
"is_changeable": true,
"refund_policy": "Non-refundable",
"change_policy": "Changeable (conditions apply)",
"checked_baggage": {
"pieces": 123,
"weight": 123,
"weight_unit": "KG",
"dimensions": "<string>",
"description": "1 bag, 23kg included"
},
"carry_on_baggage": {
"pieces": 123,
"weight": 123,
"weight_unit": "KG",
"dimensions": "<string>",
"description": "1 bag, 23kg included"
},
"extra_baggage_options": [
{
"id": "<string>",
"pieces": 123,
"weight": 123,
"weight_unit": "<string>",
"is_included": true,
"price_per_bag": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "<string>",
"segment_id": "<string>",
"journey_id": "<string>"
}
],
"extra_carry_on_options": [
{
"id": "<string>",
"pieces": 123,
"weight": 123,
"weight_unit": "<string>",
"is_included": true,
"price_per_bag": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"total_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "<string>",
"segment_id": "<string>",
"journey_id": "<string>"
}
]
},
"fare_change_notice": {
"original_brand": "MAIN SELECT",
"new_brand": "MAIN CABIN",
"refundability_changed": true,
"text": "<string>"
},
"quote_id": "exch_7a1c93f0",
"session_reference": "exch_7a1c93f0",
"expires_at": "2026-06-01T13:04:56Z",
"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 would refund 1050.00 USD, and only 789.00 is still refundable on the original payment. It can't be refunded automatically. Confirming this exchange sends it to Jinko support, who will complete it and refund you."
},
"code": "funds_unavailable"
}{
"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 before committing. customer_amounts states it in the customer’s own figures: what they paid for the ticket (original_fare), the new ticket’s value (new_fare), the airline’s change fee (penalty_amount, absent when there is none), exactly what is charged (total_due) or refunded (total_refund), and the part of the original fare the airline keeps as a credit (EMD) in the traveller’s name after an exchange to a cheaper fare (residual_value, present only when the airline reports one; it is not refunded to the card and not part of total_due or total_refund). They add up: original_fare + total_due − total_refund = new_fare + penalty_amount + residual_value, with residual_value counted as 0 when absent. The top-level fare_difference, original_fare, new_fare and penalty_amount are the supplier’s figures and are deprecated: use customer_amounts.* instead.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
Response
Price a specific exchange offer
What the customer's money does: ADD_COLLECT — they pay total_due; REFUND — they get total_refund back; EVEN — nothing moves. It is the customer's outcome, which can differ from the supplier's. The list may grow: handle a value you do not know.
"ADD_COLLECT"
Read the exchange here: the customer's own figures, all in the booking's charge currency. Absent when the platform cannot state them; the legacy fields beside it are then all there is. They add up to the cent: original_fare + total_due - total_refund = new_fare + penalty_amount + residual_value, an absent figure counting as 0. total_due and total_refund are exactly what is charged to or refunded on the customer's payment, the same figures as the top-level ones; supplier service fees are never part of them. Baggage prices in new_fare_details are airline information for buying bags; they are not part of total_due.
Show child attributes
Show child attributes
Deprecated: use customer_amounts instead. The supplier's base-fare difference between the new and the original ticket, converted to the booking's charge currency at the rate pinned when the booking was priced. It does not reconcile with the other figures: new_fare - original_fare need not equal it, and it is not what the customer pays — total_due / total_refund are.
Show child attributes
Show child attributes
Deprecated: use customer_amounts.penalty_amount instead. The change fee as the supplier states it, converted at the booking's pinned rate. On some bookings it is the supplier's own booking change fee, which Jinko absorbs: it is not part of total_due, and adding it to a fare difference overstates what the customer pays.
Show child attributes
Show child attributes
Deprecated: use customer_amounts.original_fare instead. The supplier's value of the ticket being exchanged, converted at the booking's pinned rate. It is not necessarily what the customer paid.
Show child attributes
Show child attributes
Deprecated: use customer_amounts.new_fare instead. The supplier's price of the new fare, converted at the booking's pinned rate. The legacy figures do not add up to it.
Show child attributes
Show child attributes
Exactly what the customer is charged for this exchange, in the booking's charge currency. Supplier service fees are never part of it.
Show child attributes
Show child attributes
Exactly what goes back to the customer's original payment, in the booking's charge currency.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
This price’s quote. Pass it as quote_id to exchange_commit when committing the same offer after a refused price, to request manual handling.
"exch_7a1c93f0"
Deprecated: use quote_id instead. Same value.
"exch_7a1c93f0"
"2026-06-01T13:04:56Z"
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.
