curl --request POST \
--url https://api.gojinko.com/v1/trip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "htl_2d67a7441c60e5de",
"special_requests": [
"Expected arrival around 11:30 PM.",
"A quiet room on a high floor, if available."
]
}
}
'import requests
url = "https://api.gojinko.com/v1/trip"
payload = {
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "htl_2d67a7441c60e5de",
"special_requests": ["Expected arrival around 11:30 PM.", "A quiet room on a high floor, if available."]
}
}
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: 'htl_2d67a7441c60e5de',
special_requests: [
'Expected arrival around 11:30 PM.',
'A quiet room on a high floor, if available.'
]
}
})
};
fetch('https://api.gojinko.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.gojinko.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' => 'htl_2d67a7441c60e5de',
'special_requests' => [
'Expected arrival around 11:30 PM.',
'A quiet room on a high floor, if available.'
]
]
]),
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/trip"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\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.gojinko.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\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.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\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\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",
"type": "flight",
"description": "<string>",
"offer_id": "htl_2d67a7441c60e5de",
"trip_item_token": "of_9c1d2e:FARE_ABC",
"hotel_id": "lp1f2c3",
"special_requests": [
"<string>"
],
"booking_scope": "room_bundle",
"num_rooms": 1,
"rooms": [
{
"occupancy_number": 1,
"occupancy": {
"adults": 2,
"children_ages": [
8
]
},
"room_id": "<string>",
"mapped_room_id": 123,
"room_name": "Superior Double",
"rate_id": "<string>",
"board_type": "BB",
"board_name": "Breakfast Included",
"max_occupancy": 123,
"taxes_and_fees": [
{
"amount": 164.49,
"currency": "EUR",
"amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "19, VAT National taxes on accommodation",
"included": true,
"display": "EUR 164.49"
}
],
"policies": [
{
"type": "<string>",
"description": "<string>",
"fee_amount": 123,
"fee_currency": "<string>",
"fee_amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
}
],
"is_refundable": true,
"cancellation_policy": [
{
"cancel_time": "2026-08-18T10:00:00+02:00",
"amount": 606.13,
"currency": "EUR",
"type": "amount",
"display": "EUR 606.13",
"amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"percent": 50,
"nights": 1
}
],
"free_cancellation_until": "<string>",
"payment_types": [
"pay_now"
],
"remarks": "<string>"
}
],
"price": 545.55,
"currency": "EUR",
"price_display": "EUR 545.55",
"price_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
}
],
"travelers": [
{
"traveler_ref": "pax_1",
"pax_ref_id": "pax_1",
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "MALE",
"traveler_type": "adult",
"passenger_type": "ADULT",
"identity_documents": {
"passport": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
},
"known_traveler_number": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
},
"redress_number": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
}
}
}
],
"contact": {
"email": "<string>",
"phone": "<string>",
"title": "<string>"
},
"hotel_room_guests": {},
"totals": {
"currency": "USD",
"total": 318.4
}
}{
"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": "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>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "INVALID_PHONE_NUMBER",
"message": "phone number must be in international format with a leading + and country code, for example +12025550147",
"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"
}
}trip
Create and manage a trip: add or remove items and set travelers
curl --request POST \
--url https://api.gojinko.com/v1/trip \
--header 'Content-Type: application/json' \
--header 'X-API-Key: <api-key>' \
--data '
{
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "htl_2d67a7441c60e5de",
"special_requests": [
"Expected arrival around 11:30 PM.",
"A quiet room on a high floor, if available."
]
}
}
'import requests
url = "https://api.gojinko.com/v1/trip"
payload = {
"trip_id": "trip_1048576",
"add_item": {
"trip_item_token": "htl_2d67a7441c60e5de",
"special_requests": ["Expected arrival around 11:30 PM.", "A quiet room on a high floor, if available."]
}
}
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: 'htl_2d67a7441c60e5de',
special_requests: [
'Expected arrival around 11:30 PM.',
'A quiet room on a high floor, if available.'
]
}
})
};
fetch('https://api.gojinko.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.gojinko.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' => 'htl_2d67a7441c60e5de',
'special_requests' => [
'Expected arrival around 11:30 PM.',
'A quiet room on a high floor, if available.'
]
]
]),
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/trip"
payload := strings.NewReader("{\n \"trip_id\": \"trip_1048576\",\n \"add_item\": {\n \"trip_item_token\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\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.gojinko.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\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.gojinko.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\": \"htl_2d67a7441c60e5de\",\n \"special_requests\": [\n \"Expected arrival around 11:30 PM.\",\n \"A quiet room on a high floor, if available.\"\n ]\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",
"type": "flight",
"description": "<string>",
"offer_id": "htl_2d67a7441c60e5de",
"trip_item_token": "of_9c1d2e:FARE_ABC",
"hotel_id": "lp1f2c3",
"special_requests": [
"<string>"
],
"booking_scope": "room_bundle",
"num_rooms": 1,
"rooms": [
{
"occupancy_number": 1,
"occupancy": {
"adults": 2,
"children_ages": [
8
]
},
"room_id": "<string>",
"mapped_room_id": 123,
"room_name": "Superior Double",
"rate_id": "<string>",
"board_type": "BB",
"board_name": "Breakfast Included",
"max_occupancy": 123,
"taxes_and_fees": [
{
"amount": 164.49,
"currency": "EUR",
"amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"description": "19, VAT National taxes on accommodation",
"included": true,
"display": "EUR 164.49"
}
],
"policies": [
{
"type": "<string>",
"description": "<string>",
"fee_amount": 123,
"fee_currency": "<string>",
"fee_amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
}
],
"is_refundable": true,
"cancellation_policy": [
{
"cancel_time": "2026-08-18T10:00:00+02:00",
"amount": 606.13,
"currency": "EUR",
"type": "amount",
"display": "EUR 606.13",
"amount_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
},
"percent": 50,
"nights": 1
}
],
"free_cancellation_until": "<string>",
"payment_types": [
"pay_now"
],
"remarks": "<string>"
}
],
"price": 545.55,
"currency": "EUR",
"price_display": "EUR 545.55",
"price_money": {
"value": 41250,
"currency": "USD",
"decimal_places": 2,
"display": "USD 412.50"
}
}
],
"travelers": [
{
"traveler_ref": "pax_1",
"pax_ref_id": "pax_1",
"first_name": "John",
"last_name": "Doe",
"date_of_birth": "1990-01-15",
"gender": "MALE",
"traveler_type": "adult",
"passenger_type": "ADULT",
"identity_documents": {
"passport": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
},
"known_traveler_number": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
},
"redress_number": {
"status": "saved",
"invalid_fields": [
"passport_expiry"
]
}
}
}
],
"contact": {
"email": "<string>",
"phone": "<string>",
"title": "<string>"
},
"hotel_room_guests": {},
"totals": {
"currency": "USD",
"total": 318.4
}
}{
"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": "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>",
"field": "selections[1].quantity"
}
}{
"error": {
"code": "INVALID_PHONE_NUMBER",
"message": "phone number must be in international format with a leading + and country code, for example +12025550147",
"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"
}
}contact.title (the honorific, for example mr or ms) before 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.
Creating or editing a trip does not start pricing. A new item has no price until pricing succeeds. Call checkout to start pricing and wait for its result. Polling GET /v1/trip/{trip_id} after creation does not initiate a quote. A missing price means unpriced, never free.
Ancillaries are selected on a separate endpoint. See select-ancillaries.
A trip lapses after 24 hours with no activity, and the offers and quote inside it expire sooner. See Lifetimes and expiry.Authorizations
Body
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Optional primary adult room-contact overrides keyed by the returned hotel item_id/product_id. Each product array is non-empty and occupancy_number values are unique positive room slots; omitted slots use persisted adult travelers in order with the trip contact email. The trip must already exist because the keys refer to its items.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Response
The trip
"trip_1048576"
Where the trip is in its lifecycle, as one value for the whole trip. The booking’s progress after payment is booking_state (GET /v1/trip/{trip_id}); the four booking values below (fulfilling, fulfilled, partially_fulfilled, failed) are deprecated in favour of it and still sent. draft: being built or priced, nothing paid. fulfilling: payment was submitted and booking started. Then exactly one outcome: fulfilled (booking_state completed), partially_fulfilled (partial) or failed (failed). cancelled: replaced by a new trip when it was re-shopped. 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. quoting, quoted and fulfillment_prepared are reserved and not currently set; quote progress is in quote.status.
draft, quoting, quoted, fulfillment_prepared, fulfilling, fulfilled, partially_fulfilled, failed, cancelled, expired "draft"
["created", "add_item"]
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Show child attributes
Optional primary adult room-contact overrides keyed by the returned hotel item_id/product_id. Each product array is non-empty and occupancy_number values are unique positive room slots; omitted slots use persisted adult travelers in order with the trip contact email. The trip must already exist because the keys refer to its items.
Show child attributes
Show child attributes
Show child attributes
Show child attributes
{ "currency": "USD", "total": 318.4 }
