API
Authentication
API keys, scopes and keys that act for several operators.
Send the key on every request as Authorization: Bearer pnn_live_.... Never put a key in a URL; a key in the query string is refused.
Team owners and admins create keys in Oracle under Settings, API keys. A key is shown once, has the scopes ticked when it was made and an expiry. Write scopes are off on a new key unless ticked.
Operators on a key
One key can cover several operators: the ones its creator owns or administers and picked for it. Requests act for those where the creator is still owner or admin (none left: 401). Reads return every operator's data, and every booking, manifest passenger and sales row has a partner (id, name). Add partner_id to a read for one operator; an id that is not one of the key's operators answers 404. Operators sharing one booking system account are shown once. GET /api/v1/me lists the key's operators.
Reads that take partner_id:
- GET /api/v1/bookings
- GET /api/v1/bookings/{id}
- GET /api/v1/manifest
- GET /api/v1/sales
- GET /api/v1/analytics/tours
- GET /api/v1/analytics/sites
- GET /api/v1/tours
- GET /api/v1/tours/{id}
- GET /api/v1/tours/{id}/availability
Scopes:
bookings:read(Bookings): List and read your Panion bookings. No guest email or phone.manifest:read(Manifest): Departures for a day with passengers and check-in state, from every channel.guests.contact:read(Guest contact details): Adds guest email and phone to bookings and the manifest. Off unless you need it.finance:read(Sales): Daily sales totals per channel.analytics:read(Analytics): Your tours' funnel and sales on every site and channel they are sold on, plus traffic for the sites you are on. Owners of a site also see every tour sold there.tours:read(Tours): The tours your sites sell (your own and the ones you resell): content, From price, season and live availability. Public data; a site can also read it with its publishable widget key.checkins:write(Check guests in (write)): Mark a manifest booking checked in or a no-show, or clear it. Never changes the booking.payment_links:write(Send balance payment links (write)): Email the guest a link to pay the balance still owed. Panion decides the amount. Never a rebook link.bookings.cancel:write(Cancel bookings with policy refund (write)): Cancel a live booking: the seats are released in your booking system and the guest gets a full refund, exactly as Cancel and refund in Oracle. Cannot be undone.bookings.reschedule:write(Reschedule bookings (write)): Move a live booking to another available date or departure at the same price. Never charges or refunds; a different price is refused.
Guest email and phone appear only with guests.contact:read. Without it those keys are absent.
GET /api/v1/me
The key and the operators it acts for.
Returns the key's name, scopes and expiry, and every operator it acts for right now (partners).
Scope: any valid key.
Response fields (200):
key(object)id(string): Public key id (the part after pnn_live_).name(string)scopes(array)created_at(string, ISO 8601 date-time)expires_at(string, ISO 8601 date-time)
partner(object): The first ofpartners, by name (kept for one-operator clients).id(string)name(string)
partners(array): Every operator this key acts for right now: the operators it was created for where its creator is still owner or admin.- each item:
id(string)name(string)
- each item:
Example: A key with read scopes
curl "https://www.panion.travel/api/v1/me" \
-H "Authorization: Bearer $PANION_API_KEY"{
"key": {
"id": "k7h2m4p9",
"name": "Front desk sync",
"scopes": [
"bookings:read",
"manifest:read"
],
"created_at": "2026-10-01T08:00:00Z",
"expires_at": "2027-10-01T08:00:00Z"
},
"partner": {
"id": "2b7e1516-28ae-4d2a-9f15-88094f3c4f3c",
"name": "Arctic Tours"
},
"partners": [
{
"id": "2b7e1516-28ae-4d2a-9f15-88094f3c4f3c",
"name": "Arctic Tours"
}
]
}Responses:
- 200: OK
- 400: Invalid request
- 401: Missing, invalid, expired or revoked key
- 403: The key lacks the scope
- 429: Rate limited (300 requests per minute per key)