Create and manage a trip — add or remove items, set travelers, select ancillaries
curl --request POST \
--url https://api.example.com/v1/trip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "tok_flt_9f3b2a17"
}
}
'import requests
url = "https://api.example.com/v1/trip"
payload = {
"trip_id": "trip_1048576",
"add_item": { "trip_item_token": "tok_flt_9f3b2a17" }
}
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', add_item: {trip_item_token: 'tok_flt_9f3b2a17'}})
};
fetch('https://api.example.com/v1/trip', 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/trip",
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',
'add_item' => [
'trip_item_token' => 'tok_flt_9f3b2a17'
]
]),
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/trip"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\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/trip")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/trip")
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 \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\n }\n}"
response = http.request(request)
puts response.read_body{
"trip_id": "trip_1048576",
"status": "draft",
"actions_performed": [
"created",
"add_item"
],
"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
}
}
],
"travelers": [
{
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "MALE",
"passenger_type": "ADULT"
}
],
"contact": {
"email": "<string>",
"phone": "<string>",
"title": "<string>"
},
"totals": {
"currency": "USD",
"total": 318.4
}
}{
"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": "TRIP_EXPIRED",
"message": "This trip expired after 24 hours without activity and cannot be modified.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"status": "expired"
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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"
}
}Cart & Payment
trip
Create and manage a trip, add or remove items, set travelers, select ancillaries
POST
/
v1
/
trip
Create and manage a trip — add or remove items, set travelers, select ancillaries
curl --request POST \
--url https://api.example.com/v1/trip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "tok_flt_9f3b2a17"
}
}
'import requests
url = "https://api.example.com/v1/trip"
payload = {
"trip_id": "trip_1048576",
"add_item": { "trip_item_token": "tok_flt_9f3b2a17" }
}
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', add_item: {trip_item_token: 'tok_flt_9f3b2a17'}})
};
fetch('https://api.example.com/v1/trip', 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/trip",
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',
'add_item' => [
'trip_item_token' => 'tok_flt_9f3b2a17'
]
]),
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/trip"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\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/trip")
.header("X-API-Key", "<api-key>")
.header("Content-Type", "application/json")
.body("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/v1/trip")
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 \"add_item\": {\n \"trip_item_token\": \"tok_flt_9f3b2a17\"\n }\n}"
response = http.request(request)
puts response.read_body{
"trip_id": "trip_1048576",
"status": "draft",
"actions_performed": [
"created",
"add_item"
],
"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
}
}
],
"travelers": [
{
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "MALE",
"passenger_type": "ADULT"
}
],
"contact": {
"email": "<string>",
"phone": "<string>",
"title": "<string>"
},
"totals": {
"currency": "USD",
"total": 318.4
}
}{
"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": "TRIP_EXPIRED",
"message": "This trip expired after 24 hours without activity and cannot be modified.",
"doc_url": "https://docs.gojinko.com/concepts/errors"
},
"status": "expired"
}{
"error": {
"code": "BAD_REQUEST",
"message": "<string>",
"doc_url": "<string>"
}
}{
"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"
}
}Assemble and edit a trip before sending it to checkout. Use it to add a flight or hotel offer, set traveler details, swap one item for another, or attach ancillaries like bags and seats. Flights and hotels can sit side by side in the same trip and settle through a single checkout.
Unified trip management endpoint. In a single call you can
add_item (by trip_item_token), remove_item (by item_id), and upsert_travelers (travelers + contact). Omit trip_id to create a new trip; include it to update an existing one. Returns the resulting trip state.
Ancillaries are selected on a separate endpoint. See select-ancillaries.Authorizations
ApiKeyAuthBearerAuth
Body
application/json
Response
The trip
Example:
"trip_1048576"
Where the trip is in its lifecycle. expired is the 24-hour lapse: it is evaluated LAZILY, on the read that first observes it, so this call is where a dead trip becomes visible. Once a trip is expired, adding items, setting travelers and checkout are refused with TRIP_EXPIRED; any other state that refuses a write answers TRIP_STATE_CONFLICT and names the state here. Start a new trip — a lapsed one cannot be revived.
Available options:
draft, quoting, quoted, fulfillment_prepared, fulfilling, fulfilled, partially_fulfilled, failed, cancelled, expired Example:
"draft"
Example:
["created", "add_item"]
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Example:
{ "currency": "USD", "total": 318.4 }
