# Authentication

> API keys, scopes and keys that act for several operators.

Source: https://www.panion.travel/docs/api/authentication

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 of `partners`, 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)

Example: A key with read scopes

```sh
curl "https://www.panion.travel/api/v1/me" \
  -H "Authorization: Bearer $PANION_API_KEY"
```

```json
{
  "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)
