Operations & Finance API
The back-office surface: trip oversight and Tour Director substitution, availability overrides, the on-request queue, voucher management, refunds, settlement runs with the administration fee, batch export to your finance system with hold/release control, reporting, and the audit trail.
All endpoints are under /api/optionals/v1 and require an admin bearer token (see Authentication). All amounts are integer minor units. Every report endpoint also serves CSV via ?format=csv.
Authentication
Operations & Finance users authenticate through Keycloak using the OAuth 2.0 Authorization Code flow with PKCE and MFA, federated to your corporate identity provider (for example Microsoft Entra ID) so they sign in with their existing SSO accounts. The Experiences API never accepts user passwords directly — it validates Keycloak-issued access tokens, as described in Authentication.
On sandbox tenants (provider: mock) only, the evaluation login is POST /auth/admin with { "tenantId": "meridian", "email": "operations@meridian.example.com", "password": "<password>" }, returning { token, admin }.
Trips and oversight
All trips
GET /admin/trips?tenantId=meridian
Every trip across all brands, each with its tourDirector and brandName, plus the full Tour Director roster (for substitution pickers).
Trip detail
GET /admin/trips/{tripId}?tenantId=meridian
The complete picture for one departure: trip, Tour Director, full catalog with availability (including unavailable items), guests, orders, and transactions.
Substitute the Tour Director
PATCH /admin/trips/{tripId}/td
{ "tenantId": "meridian", "tdId": "td_12" }
Reassigns the trip to a new Tour Director. Sales already processed under the outgoing Tour Director stay attributed to them for settlement — the response makes that explicit:
{
"trip": { "...": "..." },
"previousTdId": "td_07",
"salesUnderPreviousTd": { "transactionCount": 34, "settledToPreviousTd": true }
}
The incoming Tour Director owns all future sales. The substitution is audited with the transaction count and value under the outgoing Tour Director.
Availability override
PATCH /admin/trips/{tripId}/products/{productId}/availability
Identical body and behavior to the Tour Director availability endpoint — status, capacity override, sold-out policy (block | on_request), note — available centrally for any trip.
Operations queue
On-request items
GET /admin/on-request?tenantId=meridian&status=pending
Items sold beyond the allotment under an on_request policy, with trip, guest, supplier, and value context. Filters: tripId, supplier, status (pending | confirmed).
Confirm with the supplier
POST /admin/orders/{orderId}/items/{itemId}/confirm-request
Marks an on-request item confirmed once the supplier has agreed the extra place. The guest's and Tour Director's views update from "Supplier place pending" to "Supplier confirmed". Audited as on_request.confirmed.
Supplier overview
GET /admin/suppliers?tenantId=meridian
Cross-tour allotment utilisation, pending and confirmed on-request demand, and revenue per supplier — the negotiation view for allotment reviews.
Departures needing attention
GET /admin/attention?tenantId=meridian&windowDays=14
Departures leaving within the window that need action: pending on-request items, suppliers awaiting confirmation, guest forms outstanding, reservation lists due before cut-off.
Vouchers
GET /admin/vouchers?tenantId=meridian&status=active&type=partner
POST /admin/vouchers
PATCH /admin/vouchers/{voucherId}/expiry
POST /admin/vouchers/{voucherId}/void
Batch creation supports partner vouchers (with a partnerName and codes) and goodwill vouchers, up to 500 per call:
{
"tenantId": "meridian",
"type": "partner",
"partnerName": "Atlas Rewards",
"amount": 5000,
"currency": "GBP",
"expiryDate": "2027-03-31",
"withCode": true,
"quantity": 200,
"notes": "Season partner allocation"
}
Vouchers move through active → redeemed | expired | void. Expiry can be extended per voucher (PATCH .../expiry with a new expiryDate); voiding is immediate and audited. Vouchers can be linked to a booking reference so only that party can redeem them.
Refunds
POST /admin/refunds
Same body as the Tour Director refund (transactionId, optional amount, required reason) — without the own-trip restriction, for refunds handled centrally after the tour.
Settlements
The settlement lifecycle is deliberately truthful about what the platform observes: draft → exported (payment hold requested) → released for payment. Payment runs remain in your finance system.
List settlements
GET /admin/settlements?tenantId=meridian&status=draft&tdId=td_07
All settlements with the Tour Director's name resolved, filterable by status and Tour Director.
Run a settlement
POST /admin/settlements/run
{ "tenantId": "meridian", "periodStart": "2026-08-03", "periodEnd": "2026-08-09" }
Groups every unsettled completed transaction in the period per Tour Director per currency, applies the configured administration fee, and creates draft settlements. Returns 201 with the created settlements:
{
"settlements": [
{
"id": "set_881",
"reference": "SET-2026W32-TD4471-GBP",
"tdId": "td_07",
"currency": "GBP",
"periodStart": "2026-08-03",
"periodEnd": "2026-08-09",
"lines": [
{ "category": "card_sales", "label": "Card sales", "amount": 301000, "transactionCount": 41 },
{ "category": "cash_sales", "label": "Cash collected", "amount": 96000, "transactionCount": 18 },
{ "category": "refunds", "label": "Refunds", "amount": -8500, "transactionCount": 2 },
{ "category": "admin_fee", "label": "Administration fee (3%)", "amount": -11655, "transactionCount": 0 }
],
"grossAmount": 388500,
"adminFeeAmount": 11655,
"adminFeePercent": 3,
"netPayable": 376845,
"status": "draft",
"transactionIds": ["..."]
}
]
}
Settlement detail
GET /admin/settlements/{settlementId}?tenantId=meridian
The settlement with the Tour Director's name and every included transaction — the transaction-level detail retained for audit and reconciliation.
Export to the finance system
POST /admin/settlements/export
POST /admin/settlements/export?format=csv # direct CSV download
{ "tenantId": "meridian", "settlementIds": ["set_881", "set_882"] }
Produces the accounts-payable batch: one invoice per Tour Director per period, gross settled as item lines, the administration fee as a credit line, net payable per Tour Director — and every invoice flagged to load on hold in your finance system. Returns { batchRef, csv, settlements } (or the CSV itself with format=csv), and moves the settlements to exported.
Release for payment
POST /admin/settlements/{settlementId}/release
The explicit finance action that releases an on-hold invoice for payment. Separate from export by design — export requests the hold, release lifts it. Both actions are audited with the acting user. Your finance system remains the system of record for payment runs and disbursement.
Reports
Six report endpoints, all supporting ?format=csv for spreadsheet export and from/to date filters where noted:
| Endpoint | Parameters | What it answers |
|---|---|---|
GET /admin/reports/sales | groupBy = trip | td | brand | method, from, to | Sales summary grouped by departure, Tour Director, brand, or payment method |
GET /admin/reports/products | from, to | Sales per optional experience — the product performance view |
GET /admin/reports/gratuities | from, to | Gratuity totals per recipient type and currency |
GET /admin/reports/vouchers | status, tripId, tdId | Voucher issuance and redemption |
GET /admin/reports/transactions | tripId, tdId, type, method, from, to | Transaction-level detail with full filtering |
GET /admin/reports/reconciliation | from, to | Per-currency reconciliation: gateway takings vs cash vs vouchers vs settled vs exported net — the numbers finance checks against the gateway and AP |
Audit trail
GET /admin/audit?tenantId=meridian&entityType=order&tripId=trip_301&from=2026-08-01&to=2026-08-18&limit=200
The full audit log — every login, order, payment, refund, availability change, voucher action, and settlement action, each with actor type, actor id and name, action, entity, optional structured data, and timestamp. Filters: entityType, entityId, tripId, actorId, from, to, limit.
{
"events": [
{
"id": "evt_10021",
"actorType": "admin",
"actorId": "adm_02",
"actorName": "Priya Nair",
"action": "settlement.released",
"entityType": "settlement",
"entityId": "set_881",
"createdAt": "2026-08-14T09:12:44.000Z"
}
]
}