Agency
A retailer account can be shared by several agencies — branches, franchisees, corporate travel desks or offline points of sale that all book under the same retailer partner number. The agency access key identifies which of them is behind a given request.
The hierarchy is: retailer group → retailer (partner number) → agency. A retailer belongs to at most one group; an agency belongs to one or more retailers. The agency is the level at which a booking is attributed inside a retailer, and it is independent of the sales channel, which describes how the booking was made rather than who made it.
Sending the key is what makes the distinction visible in the API. Without it, every request is attributed to the retailer as a whole.
Sending the access key
The access key is read during authentication, so it is accepted on every authenticated endpoint and always takes the same form.
On POST and PUT requests, send it in the request body:
{
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
On GET requests, send it as a query parameter:
GET /connections/find?departure_station=GBXVHBS&arrival_station=FRPARPGB&agency[access_key]=AGENCY_ACCESS_KEYAn X-Agency-Access-Key request header is accepted as an equivalent to either form, and takes precedence when both are present. It is the simpler option for a client that sets the key once per session rather than per request.
Access keys are issued per environment — production, playground and demo keys are distinct, and a key from one environment does not resolve in another.
When the key is required
By default the key is optional: a request without it authenticates as the retailer and is scoped to the retailer.
A retailer can be configured with agency_access_key_required, which makes the key mandatory on every request. Distribusion sets this flag on request. It is the right setting for a retailer whose entire traffic comes through agencies, because it prevents an unattributed booking from being created by mistake.
What the key changes
Once the key resolves, three things follow.
The agency is stamped on the records created by the request. Reservations, bookings, cancellations and amendments carry the agency that created them, permanently.
List endpoints are scoped to that agency. GET /bookings and GET /reservations return only the records belonging to the resolved agency, not every record under the retailer. Fetching a single booking or reservation by id is subject to the same restriction. Omitting the key returns the retailer's full set, which is what a back-office integration servicing all agencies should do.
Bookings become serviceable across the agencies of a retailer. Because the agency is a property of the record rather than of the credentials, a booking created by one agency can be retrieved and cancelled by another agency of the same retailer, or by the retailer itself — so a booking made on an online channel can be serviced at a counter.
Reading the agency back
Every response carrying a reservation, booking, cancellation or amendment exposes the agency as a relationship:
{
"data": {
"id": "ExampleBookingId123456",
"type": "bookings",
"relationships": {
"agency": { "data": { "id": "123", "type": "agencies" } }
}
}
}
The resolved agency is also echoed on every response as the X-Agency-ID header, which is the cheapest way to confirm that a key was accepted.
Records created before an agency key was introduced, or created without one, have no agency relationship.
Examples by endpoint
The key takes the query-param form on every GET and the body form on every POST/PUT/DELETE. The payloads below are trimmed to the agency key and enough surrounding fields to place it — each endpoint's full contract is documented on its own page.
Search
GET /connections/find
?departure_station=GBXVHBS
&arrival_station=FRPARPGB
&departure_date=2026-06-01
&pax=1
¤cy=GBP
&locale=en
&agency[access_key]=AGENCY_ACCESS_KEYGET /connections/vacancy
?marketing_carrier=AAAA
&departure_station=GBXVHBS
&arrival_station=FRPARPGB
&departure_time=2026-06-01T09:00
&arrival_time=2026-06-01T14:30
&pax=1
¤cy=GBP
&locale=en
&agency[access_key]=AGENCY_ACCESS_KEYGET /connections/seats
?marketing_carrier=AAAA
&departure_station=GBXVHBS
&arrival_station=FRPARPGB
&departure_time=2026-06-01T09:00
&arrival_time=2026-06-01T14:30
&locale=en
&agency[access_key]=AGENCY_ACCESS_KEYThe key is accepted during search so that one agency context can be carried through the whole funnel from the first request. It has no effect on the results returned.
Reservations
POST /reservations/create — this is where the agency is stamped on the record.
Request:
{
"marketing_carrier": "AAAA",
"departure_station": "GBXVHBS",
"arrival_station": "FRPARPGB",
"departure_time": "2026-06-01T09:00",
"arrival_time": "2026-06-01T14:30",
"locale": "en",
"currency": "GBP",
"passengers": [{ "type": "PNOS", "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com" }],
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
Response (excerpt):
{
"data": {
"id": "EXAMPLE1",
"type": "reservations",
"attributes": { "state": "open", "total_price": 8500, "currency": "GBP" },
"relationships": { "agency": { "data": { "id": "123", "type": "agencies" } } }
}
}
PUT /reservations/confirm — the key authenticates the request; the agency stamped at creation is the one that stays on the record and is copied to the booking.
{
"reservation_id": "EXAMPLE1",
"title": "ms",
"first_name": "Jane",
"last_name": "Smith",
"email": "jane@example.com",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
GET /reservations/{reservation_id} - returns the reservation only if it belongs to the resolved agency.
GET /reservations/EXAMPLE1
?agency[access_key]=AGENCY_ACCESS_KEYPUT /reservations/cancel:
{
"reservation_id": "EXAMPLE1",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
Payment items
GET /reservations/{reservation_id}/payment_items
Request:
GET /reservations/EXAMPLE1/payment_items
?agency[access_key]=AGENCY_ACCESS_KEYResponse:
{
"jsonapi": { "version": "1.0" },
"data": {
"id": "EXAMPLE1",
"type": "payable_objects",
"attributes": { "total_price": 6574, "total_price_excluding_fees": 0, "total_fees": 0, "currency": "EUR", "total_charged": 0, "total_allocated": 6574, "total_remaining": 0 },
"relationships": {
"payment_items": { "data": [{ "id": "PI_EXAMPLE", "type": "payment_items" }] },
"fees": { "data": [{ "id": "EXAMPLE1-PAYMENT_METHOD_SURCHARGE", "type": "fees" }] }
}
},
"included": [
{
"id": "PI_EXAMPLE",
"type": "payment_items",
"attributes": { "status": "pending", "payment_method": "credit_card", "currency_code": "EUR", "total_charged": 0, "total_allocated": 6574, "total_fees": 0, "processed_at": null, "details": {} }
}
]
}
Payment items do not carry an agency of their own — the agency sits on the reservation they belong to, and the key here controls whether that reservation is reachable at all.
POST /reservations/{reservation_id}/payment_items
A reservation holds one primary payment item (card, cash, POS terminal) and any number of secondary ones (vouchers). Adding a primary replaces the existing one.
Request:
POST /reservations/EXAMPLE1/payment_items
Content-Type: application/json
Authorization: Bearer <token>{
"payment_method": "credit_card",
"details": { "number": "TOKENIZED_CARD_NUMBER", "expiry_year": "2030", "expiry_month": "02", "security_code": "123", "holder_name": "Jane Smith", "type": "visa" },
"marketing_carrier_code": "AAAA",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
Response:
{
"jsonapi": { "version": "1.0" },
"data": {
"id": "PI_EXAMPLE",
"type": "payment_items",
"attributes": { "status": "pending", "payment_method": "credit_card", "currency_code": "EUR", "total_charged": 0, "total_allocated": 6574, "total_fees": 0, "processed_at": null, "details": {} },
"relationships": { "payable_object": { "data": { "id": "EXAMPLE1", "type": "payable_objects" } } }
}
}
DELETE /reservations/{reservation_id}/payment_items/{id}
Removing a primary payment item reallocates the remaining secondary ones across the full reservation price.
Request:
DELETE /reservations/EXAMPLE1/payment_items/PI_EXAMPLE
Content-Type: application/json
Authorization: Bearer <token>{
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
Response:
{
"jsonapi": { "version": "1.0" },
"data": {
"id": "PI_EXAMPLE",
"type": "payment_items",
"relationships": { "payable_object": { "data": { "id": "EXAMPLE1", "type": "payable_objects" } } }
}
}
Bookings
POST /bookings/create
The direct booking flow, without a reservation. Stamps the agency the same way reservations/create does.
{
"marketing_carrier": "AAAA",
"departure_station": "GBXVHBS",
"arrival_station": "FRPARPGB",
"departure_time": "2026-06-01T09:00",
"arrival_time": "2026-06-01T14:30",
"locale": "en",
"currency": "GBP",
"passengers": [{ "type": "PNOS", "first_name": "Jane", "last_name": "Smith", "email": "jane@example.com" }],
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
GET /bookings
Returns only the resolved agency's bookings.
GET /bookings
?agency[access_key]=AGENCY_ACCESS_KEY
&filter[marketing_carrier_codes][]=AAAA
&page[number]=1
&page[size]=20GET /bookings/{booking_id}
Request:
GET /bookings/ExampleBookingId123456
?agency[access_key]=AGENCY_ACCESS_KEYResponse (excerpt):
{
"data": {
"id": "ExampleBookingId123456",
"type": "bookings",
"attributes": { "state": "confirmed", "total_price": 8500, "currency": "GBP" },
"relationships": { "agency": { "data": { "id": "123", "type": "agencies" } } }
}
}
GET /bookings/{booking_id}/conditions
GET /bookings/ExampleBookingId123456/conditions
?agency[access_key]=AGENCY_ACCESS_KEY
&locale=enGET /bookings/{booking_id}/tickets
GET /bookings/ExampleBookingId123456/tickets
?agency[access_key]=AGENCY_ACCESS_KEYCancellations
GET /cancellations/conditions
GET /cancellations/conditions
?booking_id=ExampleBookingId123456
&agency[access_key]=AGENCY_ACCESS_KEYPOST /cancellations/create
{
"booking_id": "ExampleBookingId123456",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
Amendments
POST /amendments/create
{
"booking_id": "ExampleBookingId123456",
"departure_station": "GBXVHBS",
"arrival_station": "FRPARPGB",
"departure_time": "2026-06-08T09:00",
"arrival_time": "2026-06-08T14:30",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
PUT /amendments/confirm
{
"amendment_id": "AMND-EXAMPLE",
"agency": { "access_key": "AGENCY_ACCESS_KEY" }
}
GET /amendments/{amendment_id}
GET /amendments/AMND-EXAMPLE
?agency[access_key]=AGENCY_ACCESS_KEYEndpoints that do not take the key
Reference and metadata endpoints return the same data for every agency, so the key can be omitted: /stations, /connected_stations, /areas, /cities, /cards, /marketing_carriers and its sub-resources, and /price-insights.
Errors
A rejected key fails authentication and returns 401, never a validation error. Four cases produce it:
- the access key does not resolve to an agency,
- the key resolves to an agency that is not linked to the authenticating retailer,
- the key was issued for a different environment,
- the retailer has
agency_access_key_requiredset and no key was sent.
The responses are deliberately identical, so an invalid key cannot be distinguished from a key belonging to another retailer.
Getting set up
Agencies and their access keys are created by Distribusion. To onboard, send the account manager the list of agency names and the retailer partner number each one books under, and state whether the access key should be mandatory. Keys are returned per environment and are credentials — they identify a booking channel and should be handled like the retailer API key.
On this page
- Agency