API
Quick book API (restricted)
A restricted API for approved integration clients to sell Panion tours at a desk and book them after payment.
Restricted access.
The Quick book API lets an approved integration client sell Panion tours at a desk or counter: list the tours its terminal can sell, quote a sale, take payment with the payment provider, then book. Panion derives the operators and tours from the terminal; the client never names a partner or merchant.
Main path: GET /tours, GET /tours/{activityId}/slots, POST /quote (holds nothing), take payment following the cart line's payment instructions with the sale reference as the payment's reference, then POST /book. Holding seats with POST /reserve is optional, for scarce departures.
Money is integer minor units with an ISO 4217 currency. Departure times are local wall-clock times with an IANA time zone.
Base URL: https://www.panion.travel/api/quickbook/v1. Machine-readable: https://www.panion.travel/api/quickbook/v1/openapi.json (OpenAPI 3.1).
Endpoints:
- GET /api/quickbook/v1/tours: List the tours this terminal can sell on a day.
- GET /api/quickbook/v1/tours/{activityId}/slots: Start times and guest prices for a tour on a day.
- POST /api/quickbook/v1/quote: Quote a sale and get the cart line.
- POST /api/quickbook/v1/reserve: Optional: hold the seats of a quoted sale while the guest pays.
- DELETE /api/quickbook/v1/reserve/{holdRef}: Optional: release a hold.
- POST /api/quickbook/v1/book: Book a paid sale.
- GET /api/quickbook/v1/sales/{reference}: Status of a sale.
- GET /api/quickbook/v1/sales/{reference}/ticket: Reprint the ticket of a confirmed sale.
Authentication
Every call sends the key as Authorization: Bearer pqb_live_... (test keys: pqb_test_...) and the id of the payment terminal in the Quickbook-Terminal header. Panion issues the key and binds it to at least one terminal; a call naming a terminal the key is not bound to is refused. Never put the key in a URL: a key in the query string is refused.
Errors
Errors answer with a JSON body {"error": {"code", "clerkMessage", "reference"?}}, an X-Request-Id header and Cache-Control: no-store. Branch on code; show clerkMessage to the person at the desk.
- 409
sold_out: Not enough seats left on this departure. - 409
price_changed: The live price differs from the quote, and the quote is pastvalidUntil. Fromquote: a guest type the tour does not sell (read the slots again). - 503
provider_unavailable: The tour operator's booking system did not answer. Try again in a moment. - 410
hold_expired: The seat hold ran out. - 422
hold_not_supported: This tour's booking system cannot hold seats. Carry on withoutreserve: take payment and callbook. - 403
terminal_not_registered: The terminal in theQuickbook-Terminalheader is not registered, not active or not bound to this key. A missing or malformed header answers 400 with this code. - 403
tour_not_sellable_here: This terminal cannot charge for this tour's operator, so it cannot sell it. - 422
phone_required: This tour needs the guest's phone number. - 422
phone_rejected: The tour operator did not accept the phone number. - 422
payment_not_found: Panion cannot find this payment at the payment provider. Nothing was booked. - 409
payment_mismatch: The payment does not match the sale (amount, currency, merchant, reference or terminal). Nothing was booked, nothing is refunded automatically, and Panion is alerted. - 409
duplicate_payment: The sale is already paid with a different payment. The second payment is refunded. - 409
provider_refused: The tour operator refused the booking. - 401
unauthorized: The Quick book key is missing, not valid, expired or revoked, or was sent in the URL. Answers withWWW-Authenticate: Bearer realm="panion-quickbook". - 429
rate_limited: Too many requests from this terminal: 60 writes, 60 books and 300 reads per minute.Retry-Aftersays when to try again. - 400
invalid_request: The body or query does not validate (a missing field, a bad date or number). - 404
not_found: No such sale or hold for this terminal: the reference is unknown or belongs to another terminal.
When book fails after the guest has paid, it answers 200 with status: "failed", the reason (one of the codes above), moneyReturned and a clerkMessage: the payment is refunded automatically.
Sale statuses (GET /sales/{reference}): quoted, held, expired, booking, confirmed, failed.
Limits
Rate limits per terminal per minute: 60 writes (quote, reserve, release), 60 books (book, its own budget so quotes never crowd out a paid sale) and 300 reads (tours, slots, sales). Past a limit: 429 rate_limited with Retry-After.
Endpoints
Quick book: tours
The tours an integration client can sell on a day, with start times and prices.
Quick book: sales
Quote a sale, book it after payment, read its status and reprint the ticket.
Quick book: holds (optional)
Optional seat holds for scarce departures while the guest pays, and releasing them.