Bookings
Get booking details
/v1/bookingRetrieve details of an existing booking.
Lookup Options:
- By booking reference: Use
idparameter - By partner reference: Use
partner_refparameter - By accreditation: Use
accreditation+accreditation_typeparameters
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Optional | Booking reference (e.g., “PE2847391”) |
partner_ref | string | Optional | Partner’s internal reference |
accreditation | string | Optional | Accreditation number |
accreditation_type | string | Optional | Type of accreditation (required if using accreditation) |
Code Examples
curl -H "access-token: {{token}}" \ "https://apistage.projectexpedition.com/v1/booking?id=PE2847391"const response = await fetch('https://apistage.projectexpedition.com/v1/booking?id=PE2847391', { headers: { 'access-token': 'YOUR_TOKEN' }});
const data = await response.json();<?php$context = stream_context_create([ 'http' => [ 'method' => 'GET', 'header' => "access-token: YOUR_TOKEN" ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking?id=PE2847391', false, $context);$data = json_decode($response, true);Responses
200 Booking details
{ "info": { "date": "2026-07-05", "time": "10:00 am", "pickup_time": null, "latestcancellation_date": "2026-06-05", "latestcancellation_time": "10:00:00", "percent_norefund": null, "language": "English" }, "meta": { "status": "Confirmed", "product_id": "PRD102160", "booking_ref": "PE154304902", "product_type": "Tour", "voucher_html": "https://projectexpedition.com/account/voucher/PE154304902", "voucher_pdf": "https://projectexpedition.com/account/voucher/PE154304902?format=pdf" }, "operator": { "name": "Context Travel", "phone": "+1-267-477-7442", "email": "info@contexttravel.com", "business_ref": "84499b29-acf4-3ec4-d169-f9cf3b08cdcd", "notes": "Operator Notes:<br>Operator Reference: 248669<br><br>" }, "pax": { "number_travellers": "6", "notes": "", "travelers_names": [ "John Smith", "Jane Smith", "Tommy Smith", "Emma Smith", "Alex Smith", "Sam Smith" ], "travelers_names_raw": { "DEFAULT::Participant": [ { "name": "John Smith" }, { "name": "Jane Smith" }, { "name": "Tommy Smith" }, { "name": "Emma Smith" }, { "name": "Alex Smith" }, { "name": "Sam Smith" } ] }, "travellers_names_html": "<b>DEFAULT::Participant</b><br><p>1. John Smith</p><p>2. Jane Smith</p>...", "add_ons_html": null, "add_ons_raw": null, "contact_email": "john.smith@example.com", "contact_phone": "+1 5551234567" }, "pricing": { "payment_status": "Pending Invoice", "total": 615.19, "amount_paid": 0, "commission": 0, "currency": "USD", "payments": [] }, "partner": { "name": "Travel Agency", "email": "agent@travelagency.com", "company": "Travel Agency Inc", "partner_ref": "AGENCY-2025-00847" }}400 Booking not found or invalid request
{ "error": "Invalid request: booking not found"}Create a new booking
/v1/bookingCreate a new booking for a tour/activity or transfer. Payment is processed automatically based on your payment terms.
Required vs Optional Parameters
| Parameter | Required | Notes |
|---|---|---|
product_id | Yes | Product ID (e.g., “PE12031”) |
date | Yes | Tour date (YYYY-MM-DD) |
time | Yes | Tour start time |
phone | Yes | Phone number with + country code (e.g., +14155551234). Parseable E.164 numbers are normalized server-side via libphonenumber. Other formats are accepted as submitted but may be rejected downstream by carriers/suppliers. Only missing or empty values return a 400. |
adults/children/etc. | Conditional | Required based on product’s pricing model |
description | Conditional | Required for By API products that offer multiple price slots (see below) |
email | No | Contact email |
partner_ref | No | Your internal reference |
hotel_pickup | No | Pickup location (if product supports) |
language | No | Preferred tour language |
Multiple Tour Bookings
Note: Each booking request creates a single tour booking. To book multiple tours for the same travelers, submit separate API calls for each tour.
Payment Processing
How payment is handled depends on your account’s payment terms:
| Payment Term | What to Send |
|---|---|
| Credit | No payment parameters needed |
| Card on File | Uses your stored Stripe payment method |
| Default | Requires token + card_holder parameters |
For default payment terms, obtain a Stripe token via Stripe.js. Project Expedition handles PCI compliance - you only handle tokenization.
The description Parameter (API-Priced Products)
Products that use the By API pricing model may offer multiple price slots (e.g., “With tickets” vs “Without tickets”). When this is the case, the description parameter tells Project Expedition which slot to book.
How to determine the correct value:
- Call
/return_availabilityfor the product and date. - Look at the
time_with_descriptionarray in the response — each entry has adescriptionfield. - Pass the matching
descriptionstring in your booking request.
Example — Private Delphi Full Day Tour from Athens (PE48898):
{ "product_id": "PE48898", "date": "2025-07-10", "time": "8:00 am", "phone": "+30 210 1234567", "Customer (4+ Years)": "John Smith,Jane Smith", "description": "With tickets", "partner_ref": "AGENCY-2025-01234"}Tip: If the product only has a single price slot, you can omit
description. It is only required when multiple slots exist.
Transfer Booking Required Fields
| From Type | Required Fields |
|---|---|
| airport | arrival_flight_number, origin_airport |
| cruise port | cruiseline, cruiseship, ship_arrival_time |
| train station | train_number, train_origin_departure_time |
| To Type | Required Fields |
|---|---|
| airport | departure_flight_number, destination_airport, departure_flight_time |
| cruise port | departure_cruiseline, departure_cruiseship, departure_ship_time |
| train station | departure_train_number, departure_train_time |
Flight Number Format
Flight identifiers accept either the spaced form (EI 123) or the compact
form (EI123). Both are normalised server-side via
BlacklaneFlightString::parse() before dispatch to the chauffeur service.
Request Body
Required
Code Examples
# Tour Bookingcurl -X POST \ -H "access-token: {{token}}" \ -H "Content-Type: application/json" \ -d '{ "product_id": "PE12031", "date": "2025-03-15", "time": "7:00 am", "phone": "+1 555 123 4567", "email": "john.smith@example.com", "adults": "John Smith,Jane Smith", "children": "Tommy Smith,Emma Smith", "partner_ref": "PTA-2025-00847", "hotel_pickup": "The Shelbourne Hotel, St Stephen Green", "traveler_questions": "No dietary restrictions", "language": "English" }' \ "https://apistage.projectexpedition.com/v1/booking"const response = await fetch('https://apistage.projectexpedition.com/v1/booking', { method: 'POST', headers: { 'access-token': 'YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ "product_id": "PE12031", "date": "2025-03-15", "time": "7:00 am", "phone": "+1 555 123 4567", "email": "john.smith@example.com", "adults": "John Smith,Jane Smith", "children": "Tommy Smith,Emma Smith", "partner_ref": "PTA-2025-00847", "hotel_pickup": "The Shelbourne Hotel, St Stephen Green", "traveler_questions": "No dietary restrictions", "language": "English" })});
const data = await response.json();<?php$data = json_encode({ 'product_id': 'PE12031', 'date': '2025-03-15', 'time': '7:00 am', 'phone': '+1 555 123 4567', 'email': 'john.smith@example.com', 'adults': 'John Smith,Jane Smith', 'children': 'Tommy Smith,Emma Smith', 'partner_ref': 'PTA-2025-00847', 'hotel_pickup': 'The Shelbourne Hotel, St Stephen Green', 'traveler_questions': 'No dietary restrictions', 'language': 'English' });
$context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => "Content-Type: application/json\r\naccess-token: YOUR_TOKEN\r\nContent-Type: application/json", 'content' => $data ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking', false, $context);$result = json_decode($response, true);# Transfer Booking — flight identifier with space separator ("EI 123")curl -X POST \ -H "access-token: {{token}}" \ -H "Content-Type: application/json" \ -d '{ "type": "transfer", "search": "eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19", "quote_id": "a1b2c3d4e5f6789012345678901234ab", "price": 45.00, "lead_pax": "John Smith", "contact_phone": "+1 555 123 4567", "contact_email": "john.smith@example.com", "arrival_flight_number": "EI 123", "origin_airport": "JFK" }' \ "https://apistage.projectexpedition.com/v1/booking"const response = await fetch('https://apistage.projectexpedition.com/v1/booking', { method: 'POST', headers: { 'access-token': 'YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ "type": "transfer", "search": "eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19", "quote_id": "a1b2c3d4e5f6789012345678901234ab", "price": 45, "lead_pax": "John Smith", "contact_phone": "+1 555 123 4567", "contact_email": "john.smith@example.com", "arrival_flight_number": "EI 123", "origin_airport": "JFK" })});
const data = await response.json();<?php$data = json_encode({ 'type': 'transfer', 'search': 'eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19', 'quote_id': 'a1b2c3d4e5f6789012345678901234ab', 'price': 45.00, 'lead_pax': 'John Smith', 'contact_phone': '+1 555 123 4567', 'contact_email': 'john.smith@example.com', 'arrival_flight_number': 'EI 123', 'origin_airport': 'JFK' });
$context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => "Content-Type: application/json\r\naccess-token: YOUR_TOKEN\r\nContent-Type: application/json", 'content' => $data ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking', false, $context);$result = json_decode($response, true);# Transfer Booking — compact flight identifier ("EI123" — no space).# Both spaced and compact forms are accepted; the server normalises# before dispatch to the chauffeur service.curl -X POST \ -H "access-token: {{token}}" \ -H "Content-Type: application/json" \ -d '{ "type": "transfer", "search": "eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19", "quote_id": "a1b2c3d4e5f6789012345678901234ab", "price": 45.00, "lead_pax": "John Smith", "contact_phone": "+1 555 123 4567", "contact_email": "john.smith@example.com", "arrival_flight_number": "EI123", "origin_airport": "JFK" }' \ "https://apistage.projectexpedition.com/v1/booking"const response = await fetch('https://apistage.projectexpedition.com/v1/booking', { method: 'POST', headers: { 'access-token': 'YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ "type": "transfer", "search": "eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19", "quote_id": "a1b2c3d4e5f6789012345678901234ab", "price": 45, "lead_pax": "John Smith", "contact_phone": "+1 555 123 4567", "contact_email": "john.smith@example.com", "arrival_flight_number": "EI123", "origin_airport": "JFK" })});
const data = await response.json();<?php$data = json_encode({ 'type': 'transfer', 'search': 'eyJmcm9tIjp7InR5cGUiOiJhaXJwb3J0In19', 'quote_id': 'a1b2c3d4e5f6789012345678901234ab', 'price': 45.00, 'lead_pax': 'John Smith', 'contact_phone': '+1 555 123 4567', 'contact_email': 'john.smith@example.com', 'arrival_flight_number': 'EI123', 'origin_airport': 'JFK' });
$context = stream_context_create([ 'http' => [ 'method' => 'POST', 'header' => "Content-Type: application/json\r\naccess-token: YOUR_TOKEN\r\nContent-Type: application/json", 'content' => $data ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking', false, $context);$result = json_decode($response, true);Responses
200 Booking created successfully
400 Booking failed
{ "error": "Phone number missing"}Update a booking
/v1/bookingRequest updates to an existing booking.
Important: This endpoint does NOT automatically apply changes. All update requests are submitted for manual review by our reservations team.
How to Request a Modification
- Provide the booking
id(reference number) - Describe the requested changes in the
notesfield - Our team will review and respond within 24-48 hours
Not Supported via API
The following changes cannot be applied automatically:
- Date or time changes
- Passenger name changes
- Quantity or participant changes
For time-sensitive changes, contact partners@projectexpedition.com directly.
Request Body
Required
Code Examples
curl -X PUT \ -H "access-token: {{token}}" \ -H "Content-Type: application/json" \ -d '{ "id": "PE2847391", "notes": "Please change pickup time to 7:30 am" }' \ "https://apistage.projectexpedition.com/v1/booking"const response = await fetch('https://apistage.projectexpedition.com/v1/booking', { method: 'PUT', headers: { 'access-token': 'YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ "id": "PE2847391", "notes": "Please change pickup time to 7:30 am" })});
const data = await response.json();<?php$data = json_encode({ 'id': 'PE2847391', 'notes': 'Please change pickup time to 7:30 am' });
$context = stream_context_create([ 'http' => [ 'method' => 'PUT', 'header' => "Content-Type: application/json\r\naccess-token: YOUR_TOKEN\r\nContent-Type: application/json", 'content' => $data ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking', false, $context);$result = json_decode($response, true);Responses
200 Update request received
Cancel a booking
/v1/bookingRequest cancellation of an existing booking.
Important: This creates a cancellation REQUEST, not an immediate cancellation.
The notes field in the response indicates refund eligibility based on the cancellation window.
Request Body
Required
Code Examples
curl -X DELETE \ -H "access-token: {{token}}" \ -H "Content-Type: application/json" \ -d '{ "reference_id": "PE2847391", "reason": "Customer requested cancellation due to schedule change" }' \ "https://apistage.projectexpedition.com/v1/booking"const response = await fetch('https://apistage.projectexpedition.com/v1/booking', { method: 'DELETE', headers: { 'access-token': 'YOUR_TOKEN', 'Content-Type': 'application/json' }, body: JSON.stringify({ "reference_id": "PE2847391", "reason": "Customer requested cancellation due to schedule change" })});
const data = await response.json();<?php$data = json_encode({ 'reference_id': 'PE2847391', 'reason': 'Customer requested cancellation due to schedule change' });
$context = stream_context_create([ 'http' => [ 'method' => 'DELETE', 'header' => "Content-Type: application/json\r\naccess-token: YOUR_TOKEN\r\nContent-Type: application/json", 'content' => $data ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking', false, $context);$result = json_decode($response, true);Responses
200 Cancellation request processed
400 Cancellation failed
Get recent booking updates
/v1/booking_updatesReturns bookings that have been modified within a given period.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
period | integer | Optional | Number of days to look back (default 7) - Default: 7 |
Code Examples
curl -H "access-token: {{token}}" \ "https://apistage.projectexpedition.com/v1/booking_updates?period=14"const response = await fetch('https://apistage.projectexpedition.com/v1/booking_updates?period=14', { headers: { 'access-token': 'YOUR_TOKEN' }});
const data = await response.json();<?php$context = stream_context_create([ 'http' => [ 'method' => 'GET', 'header' => "access-token: YOUR_TOKEN" ]]);
$response = file_get_contents('https://apistage.projectexpedition.com/v1/booking_updates?period=14', false, $context);$data = json_decode($response, true);