curl --request POST \
--url https://api.example.com/v1/checkout \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"fail_on_price_change": false,
"intent": {
"user_intent": "find a cheap flight to Tokyo"
}
}
'import requests
url = "https://api.example.com/v1/checkout"
payload = {
"trip_id": "trip_1048576",
"fail_on_price_change": False,
"intent": { "user_intent": "find a cheap flight to Tokyo" }
}
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({
trip_id: 'trip_1048576',
fail_on_price_change: false,
intent: {user_intent: 'find a cheap flight to Tokyo'}
})
};
fetch('https://api.example.com/v1/checkout', 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/checkout",
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([
'trip_id' => 'trip_1048576',
'fail_on_price_change' => false,
'intent' => [
'user_intent' => 'find a cheap flight to Tokyo'
]
]),
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/checkout"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\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/checkout")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/checkout")
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 \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\n }\n}"
response = http.request(request)
puts response.read_body{
"session_id": "cs_1048576",
"checkout_url": "https://book.gojinko.com/checkout?sid=1048576",
"status": "ready",
"expires_at": "2026-06-01T12:39:56Z",
"payment_type": "checkout",
"total_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"items": [
{
"item_id": "itm_4b91c2",
"kind": "flight",
"offer_id": "htl_2d67a7441c60e5de",
"trip_item_token": "of_9c1d2e:FARE_ABC",
"hotel_id": "lp1f2c3",
"price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"pax_count": 1,
"available_ancillaries": [
{
"offer_id": "anc_bag_20kg",
"type": "bag",
"label": "bag&1 x large 55 x 40 x 20 cm&Includes Speedy Boarding",
"display_label": "bag, 1 x large 55 x 40 x 20 cm, Includes Speedy Boarding",
"description": "<string>",
"price_per_unit": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"per_pax": true,
"max_quantity": 2,
"paid_at": "now"
}
],
"selected_ancillaries": [
{
"offer_id": "anc_bag_20kg",
"pax_ref_id": "pax_1",
"quantity": 1
}
],
"price_changed": true,
"original_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"required_attributes": {
"source": "provider",
"per_passenger": [
"PassportNumber",
"PassportExpiryDate",
"DateOfBirth"
],
"booking": [
"BillingAddress",
"PostCode"
],
"per_passenger_conditional": [
"Nationality"
],
"booking_conditional": [
"<string>"
]
},
"hotel_terms": {
"terms_as_of": "search",
"taxes_breakdown": [
{
"amount": 164.49,
"currency": "EUR",
"description": "19, VAT National taxes on accommodation",
"included": true
}
],
"cancellation_schedule": [
{
"cancel_time": "2026-08-18T10:00:00+02:00",
"amount": 606.13,
"currency": "EUR",
"type": "amount"
}
],
"free_cancellation_until": "2026-08-18T10:00:00+02:00",
"is_refundable": false,
"board_type": "RO",
"board_name": "Room Only",
"payment_types": [
"NUITEE_PAY"
],
"room_name": "Superior Double",
"room_capacity": 2
}
}
],
"agent_spt_params": {
"max_amount": 259449,
"currency": "USD",
"stripe_profile": "<string>",
"expires_at": "2026-06-10T13:04:56Z"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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": "PRICE_CHANGED",
"message": "1 item was re-priced between the quote and checkout.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"items": [
{
"item_id": "itm_4b91c2",
"price": {
"amount": 210.4,
"currency": "USD"
},
"original_price": {
"amount": 188.65,
"currency": "USD"
}
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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"
}
}checkout
Checkout a trip, returns a checkout URL the user opens to pay, plus the Shared Payment Token params an agent can use to pay programmatically
curl --request POST \
--url https://api.example.com/v1/checkout \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"fail_on_price_change": false,
"intent": {
"user_intent": "find a cheap flight to Tokyo"
}
}
'import requests
url = "https://api.example.com/v1/checkout"
payload = {
"trip_id": "trip_1048576",
"fail_on_price_change": False,
"intent": { "user_intent": "find a cheap flight to Tokyo" }
}
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({
trip_id: 'trip_1048576',
fail_on_price_change: false,
intent: {user_intent: 'find a cheap flight to Tokyo'}
})
};
fetch('https://api.example.com/v1/checkout', 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/checkout",
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([
'trip_id' => 'trip_1048576',
'fail_on_price_change' => false,
'intent' => [
'user_intent' => 'find a cheap flight to Tokyo'
]
]),
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/checkout"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\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/checkout")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/checkout")
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 \"trip_id\": \"trip_1048576\",\n \"fail_on_price_change\": false,\n \"intent\": {\n \"user_intent\": \"find a cheap flight to Tokyo\"\n }\n}"
response = http.request(request)
puts response.read_body{
"session_id": "cs_1048576",
"checkout_url": "https://book.gojinko.com/checkout?sid=1048576",
"status": "ready",
"expires_at": "2026-06-01T12:39:56Z",
"payment_type": "checkout",
"total_amount": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"items": [
{
"item_id": "itm_4b91c2",
"kind": "flight",
"offer_id": "htl_2d67a7441c60e5de",
"trip_item_token": "of_9c1d2e:FARE_ABC",
"hotel_id": "lp1f2c3",
"price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"pax_count": 1,
"available_ancillaries": [
{
"offer_id": "anc_bag_20kg",
"type": "bag",
"label": "bag&1 x large 55 x 40 x 20 cm&Includes Speedy Boarding",
"display_label": "bag, 1 x large 55 x 40 x 20 cm, Includes Speedy Boarding",
"description": "<string>",
"price_per_unit": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"per_pax": true,
"max_quantity": 2,
"paid_at": "now"
}
],
"selected_ancillaries": [
{
"offer_id": "anc_bag_20kg",
"pax_ref_id": "pax_1",
"quantity": 1
}
],
"price_changed": true,
"original_price": {
"amount": 123,
"value": 41250,
"currency": "USD",
"decimal_places": 2
},
"required_attributes": {
"source": "provider",
"per_passenger": [
"PassportNumber",
"PassportExpiryDate",
"DateOfBirth"
],
"booking": [
"BillingAddress",
"PostCode"
],
"per_passenger_conditional": [
"Nationality"
],
"booking_conditional": [
"<string>"
]
},
"hotel_terms": {
"terms_as_of": "search",
"taxes_breakdown": [
{
"amount": 164.49,
"currency": "EUR",
"description": "19, VAT National taxes on accommodation",
"included": true
}
],
"cancellation_schedule": [
{
"cancel_time": "2026-08-18T10:00:00+02:00",
"amount": 606.13,
"currency": "EUR",
"type": "amount"
}
],
"free_cancellation_until": "2026-08-18T10:00:00+02:00",
"is_refundable": false,
"board_type": "RO",
"board_name": "Room Only",
"payment_types": [
"NUITEE_PAY"
],
"room_name": "Superior Double",
"room_capacity": 2
}
}
],
"agent_spt_params": {
"max_amount": 259449,
"currency": "USD",
"stripe_profile": "<string>",
"expires_at": "2026-06-10T13:04:56Z"
}
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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": "PRICE_CHANGED",
"message": "1 item was re-priced between the quote and checkout.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"items": [
{
"item_id": "itm_4b91c2",
"price": {
"amount": 210.4,
"currency": "USD"
},
"original_price": {
"amount": 188.65,
"currency": "USD"
}
}
]
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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"
}
}Authorizations
Body
"trip_1048576"
Refuse checkout if any item was re-priced since the quote. When true and at least one item moved, the call answers 409 PRICE_CHANGED listing those items and does nothing else — the trip stays quoted, so you can re-read it and check out again without the flag to accept the new price. Default false: checkout proceeds at the new price and the moved items carry price_changed / original_price.
false
Show child attributes
Show child attributes
Response
Checkout session
"cs_1048576"
"https://book.gojinko.com/checkout?sid=1048576"
Checkout session state — "ready", "pending" or "failed".
"ready"
When the locked quote behind this checkout expires (RFC 3339). Roughly five minutes from the call — pay before it passes. This is NOT the lifetime of checkout_url, which the platform keeps openable for longer. After this instant the platform REFUSES to take payment rather than charging a stale price: POST /v1/agent_payment/submit answers 410 QUOTE_EXPIRED and no payment object is created. To recover, call POST /v1/checkout again on the same trip — it re-quotes — and pay against the new expires_at. The hosted page offers the same refresh in one click.
"2026-06-01T12:39:56Z"
How this checkout will be paid. checkout — send the user to checkout_url. agent — pay programmatically: mint a Shared Payment Token against agent_spt_params and call POST /v1/agent_payment/submit. intent — a payment intent is already authorized against the cart and no further action is needed from you.
intent, checkout, agent "checkout"
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Parameters to scope a Shared Payment Token to, so an agent can pay programmatically instead of opening checkout_url: mint the token against these, then call POST /v1/agent_payment/submit with trip_id and the token. Absent from the checkout response whenever the cart is quoted in a currency other than USD — Shared Payment Tokens are US-only — and that absence means agent-pay is unavailable for this cart, not that the field was dropped by accident. Such a cart is paid through checkout_url. The human checkout path ignores this object.
Show child attributes
Show child attributes
