Skip to main content

Quickstart

Make your first sandbox booking in about five minutes: search, recheck, book, read the booking and cancel it. The sandbox only talks to the providers' test systems, so nothing is charged and no real ride is booked. Pick your language once; every sample on the page follows it.

Before you start​

  1. Get a sandbox key. Ask your Pathfndr account manager, or write to [email protected]. Sandbox keys start with tp_test_. The key is shown once: keep it in a secrets manager, never in code.
  2. Set two environment variables, TP_BASE_URL and TP_API_KEY. All samples read them.
  3. Use a pickup date a few days ahead and obviously fake traveller data (Jane Doe, [email protected]).

The Python samples use requests; the Node.js samples use the built-in fetch (Node 18 or later).

Shell
export TP_BASE_URL="https://transfers-sandbox.pathfndr.io"
export TP_API_KEY="tp_test_xxxxxxxx" # your sandbox key
curl -s "$TP_BASE_URL/health"
# {"status":"healthy"}

Step 1: Search for offers​

Search an airport arrival from Mumbai airport (BOM) to a hotel. One call queries every provider enabled for your key in parallel and returns one list, cheapest first, priced in the currency you send.

Keep three values of the offer the customer picks: provider, rate_key and offer_token. The token is opaque and valid for 24 hours, for your key only.

A provider that fails or has nothing for the route is listed in errors[] while the others still return offers, so a 200 with a non-empty errors[] is normal.

Search reference · Transfer types

POST/v1/search
curl -s -X POST "$TP_BASE_URL/v1/search" \
-H "X-API-Key: $TP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"transfer_type": "airport",
"iata": "BOM",
"source_type": "air",
"place": {"lat": 18.9217, "lng": 72.8332, "name": "The Taj Mahal Palace",
"address": "Apollo Bunder, Colaba, Mumbai 400001"},
"arrival_date": "2026-11-26",
"arrival_time": "10:30",
"adults": 2,
"currency": "INR"
}' > search.json

jq '.offers[0] | {provider, rate_key, offer_token}' search.json > offer.json
200 OK (trimmed to one offer)
{
"request_id": "6f1c1e0a-3c55-4a59-9b8e-1f0a2a5d9c11",
"transfer_type": "airport",
"offers": [
{
"provider": "provider_a",
"direction": "arrival",
"rate_key": "d320deaaed65343ed2a5b8fac337a7dd",
"offer_token": "ot1.gAAAAAB...",
"price": {"total": 2508.37, "currency": "INR", "taxes_included": true},
"vehicle": {"category": "Sedan", "max_passengers": 3, "max_bags": 3},
"cancellation_summary": "100% refund if cancelled at least 24h before pickup",
"flight_info_required": true
}
],
"errors": [],
"meta": {"offer_count": 24, "currencies": ["INR"], "sort": "price_asc"}
}

Step 2: Recheck the offer​

Recheck immediately before booking. It confirms the offer can still be booked and returns the current price.

  • available: true and price_changed: false: book.
  • price_changed: true: show the new total_price to the customer and book only once they accept.
  • available: false: do not book; search again.

Book with the recheck's offer_token, not the search's: it carries the current price.

Recheck reference · Offer expiry

POST/v1/transfer/recheck
jq '{provider_context: .}' offer.json \
| curl -s -X POST "$TP_BASE_URL/v1/transfer/recheck" \
-H "X-API-Key: $TP_API_KEY" -H "Content-Type: application/json" \
--data-binary @- > recheck.json

jq '{available, price_changed, total_price, currency}' recheck.json
200 OK
{
"available": true,
"price_changed": false,
"total_price": 2509.96,
"currency": "INR",
"cancellation_policy": null,
"offer_token": "ot1.gAAAAAB...",
"error": null
}

Step 3: Book​

Book with the recheck's offer_token, the lead traveller and your own order reference in internal_reference. Airport offers with flight_info_required: true also need the flight.

Book is idempotent per internal_reference: if the call times out, re-send the identical request and you get the original booking back, never a second one (Idempotency & retries). Allow up to 150 seconds.

status is completed, pending (poll booking details), failed (nothing was booked) or unknown (do not rebook; re-send the identical request later). Store the whole supplier_reference object: booking details and cancel need it unchanged.

Book reference

POST/v1/transfer/book
jq -n --slurpfile o offer.json --slurpfile r recheck.json '{
provider_context: {provider: $o[0].provider, rate_key: $o[0].rate_key,
offer_token: $r[0].offer_token},
travellers: [{title: "Ms", first_name: "Jane", last_name: "Doe", is_lead: true,
email: "[email protected]", phone: "+442079460000",
phone_country_code: "GB"}],
internal_reference: "TEST-0001",
flight_info: {airline: "AI", flight_number: "AI101",
flight_datetime: "2026-11-26T09:30"}
}' > book-request.json

curl -s -X POST "$TP_BASE_URL/v1/transfer/book" \
-H "X-API-Key: $TP_API_KEY" -H "Content-Type: application/json" \
--max-time 150 --data-binary @book-request.json > book.json

jq '{status, supplier_booking_ref, total_price, currency}' book.json
200 OK (booking_details trimmed)
{
"status": "completed",
"supplier_booking_id": "01aa00bb11cc22dd33ee44ff55667781",
"supplier_booking_ref": "PRV0000001",
"supplier_reference": {
"booking_id": "01aa00bb11cc22dd33ee44ff55667781",
"confirmation_number": "PRV0000001",
"provider": "provider_a",
"booking_status": "completed",
"booking_token": "bt1.gAAAAAB..."
},
"total_price": 2509.96,
"currency": "INR",
"booking_details": {"details_version": "3"},
"error": null
}

Step 4: Read the booking​

Booking details returns the booking in one shape for every provider: status, pickup time and places, passengers, vehicle, meeting point, driver (closer to pickup) and the cancellation policy. Build your voucher from it.

Booking details guide · Reference

POST/v1/transfer/booking-details
jq '{provider_context: {provider: .supplier_reference.provider}, supplier_reference}' book.json \
| curl -s -X POST "$TP_BASE_URL/v1/transfer/booking-details" \
-H "X-API-Key: $TP_API_KEY" -H "Content-Type: application/json" \
--data-binary @- \
| jq '.booking_details.booking'
200 OK (booking section)
{
"tp_booking_ref": "TEST-0001",
"provider": "provider_a",
"supplier_confirmation_number": "PRV0000001",
"status": "confirmed",
"status_source": "supplier",
"booked_at": "2026-10-23T06:33:43+00:00"
}

Step 5: Cancel the test booking​

Always cancel the sandbox bookings you create. status is cancelled, or cancellation_pending for providers that confirm cancellations later (poll booking details until it reads cancelled). The refund is reported in the booking's currency.

That's the whole flow. Next: the Booking flow in depth, the Errors you should handle, and the Go-live checklist.

Cancellations & refunds · Reference

POST/v1/transfer/cancel
jq '{provider_context: {provider: .supplier_reference.provider},
supplier_reference, reason: "Sandbox test"}' book.json \
| curl -s -X POST "$TP_BASE_URL/v1/transfer/cancel" \
-H "X-API-Key: $TP_API_KEY" -H "Content-Type: application/json" \
--data-binary @- \
| jq '{status, cancelled, refund_amount, currency}'
200 OK
{
"status": "cancelled",
"cancelled": true,
"refund_amount": 2509.96,
"currency": "INR",
"refund_source": "supplier",
"refund_estimated": false,
"cancelled_at": "2026-10-23T06:33:47+00:00",
"cancelled_at_source": "tp_cancel",
"error": null
}