Skip to main content

High-level integration flow

Headout inventory follows a strict hierarchy: City → Product → Variant → Time Slot → Booking → Ticket

Typical end-user journey

  1. User selects a city
  2. Partner fetches all products for that city from their cached catalog data
  3. User selects a product and variant
  4. User selects date and time slot
  5. Partner fetches real-time availability
  6. User enters guest details and initiates payment
  7. A booking request is created with Headout to confirm availability of the selected slot
  8. User completes payment
  9. Booking is confirmed with Headout
  10. Ticket is generated and delivered
  11. Booking updates are received via webhooks

Product discovery, variants & policies

Cities & products

  • Products are always fetched at a city level — this is the highest aggregation level at Headout
  • The following catalog data can be cached on the partner’s side:
    • Active city list → refresh monthly
    • Categories & subcategories → refresh monthly
    • Collections → refresh monthly
    • Product list & product details → refresh daily or weekly
  • B2B APIs return a flat list of all products in no particular order — there is no ranking, tagging, or B2C grouping (e.g. bestsellers). Any such filtering or ordering must be implemented on the partner’s side.
Not all products visible on the Headout B2C surface will appear in the B2B API. If a product is missing from your listing, it could be due to one or more of the following reasons:
  • The product is intentionally hidden or marked non-bookable for partner traffic
  • The product currently has no available inventory (it would also appear unavailable on the B2C website)
  • The product has been delisted — check the current B2C website, not older cached data
  • The product’s booking flow is not yet supported in the Partner API. Currently, only NORMAL and SEATMAP inventory selection types are supported. Products requiring section-based booking, combo booking, or any other non-standard flow are not available via the Partner API

Ratings, reviews & recommendations

  • Ratings are exposed via the reviewsSummary object on every product returned by List Products and Get ProductratingsCount (total verified ratings) and averageRating (mean on a 1–5 scale).
  • Review text is not exposed via the API. If a one-time dump of review content is genuinely needed for a launch (e.g. seeding a partner-side display), this can be shared on request via your Headout SPOC.
  • Recommendations and similar-products APIs are not provided. Partners that want related-product surfaces should derive them from the catalog on their own side (e.g. by collection / category / subcategory grouping).

Inventory selection types

This subsection is relevant to API Partner accounts (booking flow). Affiliate accounts do not book through the API.
Every product carries an inventorySelectionType that tells you how date / time / seat selection is presented and which inventory endpoint to call. There are two values today; both are supported for booking.
inventorySelectionTypeWhat it meansInventory + booking flow
NORMALStandard date and time slot selection. Most products.List InventoryCreate BookingUpdate Booking
SEATMAPSeat-level selection (theatre, live entertainment).Seatmap availabilitiesList Inventory - SeatmapValidateCreate BookingUpdate Booking
Read inventorySelectionType from each product and branch your flow accordingly — never assume one type for all products. If a future value appears that isn’t in this list, treat it as unsupported for booking and fall back to displaying the product as not bookable until guidance is updated. The Headout Partner API does not expose a free-text or real-time search endpoint. Catalog discovery is structured, not query-based:
  • Start with List Cities to scope the catalog.
  • Narrow by Collections, Categories, or Subcategories.
  • Use List Products with the relevant filters to retrieve products.
If you need free-text search in your own surface, index the Products listing on your side and run search against your local index.

Variants

A single product can have multiple variants. Variants can differ by many parameters, including but not limited to:
  • Inclusions and exclusions
  • Cancellation or reschedule eligibility
  • Meeting point or pickup details
  • Ticket type and fulfillment behavior
  • Pricing and availability patterns
Variants must be treated as independent purchasable units, not as metadata. Example: The Eiffel Tower is a single product. Its variants could be:
  • Eiffel Tower – 2nd Floor Access
  • Eiffel Tower – Summit Access
  • Eiffel Tower – English Guided Tour
  • Eiffel Tower – Spanish Guided Tour
Each of these is a separate bookable unit with its own pricing, availability, and policies.

Variant metadata: properties and propertiesV2

Variants return a properties map that carries additional identifying information about that variant. This is not decorative metadata — it is a critical field.

Treat them as dynamic key-value data, not fixed schema fields.
  • properties is a plain object whose values are strings
  • propertiesV2 can usually be ignored
For example, one variant might carry a language-based property:
{
  "properties": {
    "LANGUAGE_CODE": "EN"
  },
  "propertiesV2": {}
}
Another variant might be tied to nationality or a product-specific classification:
{
  "properties": {
    "NATIONALITY": "MALAYSIAN_CITIZEN"
  },
  "propertiesV2": {}
}
{
  "properties": {
    "NUMBER_OF_ATTRACTIONS": "3_ATTRACTIONS"
  },
  "propertiesV2": {}
}
⚠️ properties is critical and must never be skipped. If a variant carries any properties, they must be displayed prominently alongside the variant name — not buried in fine print or omitted. Two variants can have different prices solely because their properties differ — by language, nationality, attraction count, or another variant-level condition. This information directly determines which variant the customer should select. If you don’t show it, customers can book the wrong variant and face issues at the venue, increasing the support load and customer dissatisfaction.

Cancellation & reschedule policies

Cancellation and reschedule behavior is defined explicitly in the Product Details API.

Eligibility and cutoff

  • cancellationPolicy.cancellable and reschedulePolicy.reschedulable are simple booleans — the operation is either allowed or not allowed.
  • cancellableUpToInMinutes / reschedulableUpToInMinutes define the cutoff before the experience start time. Requests submitted after the cutoff are not accepted.
  • Policies may differ across products and across variants of the same product. Read them from the API per variant; do not assume uniform behavior.
Partners must:
  • Read and rely on the API response
  • Surface the correct policy to users before booking
  • Not assume uniform behavior across variants

Refund handling

Refunds are a separate concern from cancellation eligibility. The cancellable flag and cancellableUpToInMinutes cutoff only determine whether Headout accepts the cancellation — they do not describe how money is returned. API Partner accounts
  • When an eligible booking is cancelled, the partner’s Headout wallet is topped up automatically with the full booking amount.
  • The partner is responsible for refunding the end customer through their own payment system. Headout does not contact or refund the end customer.
Affiliate accounts
  • When an eligible booking is cancelled, Headout refunds the end customer directly.

Inventory, pax types & pricing

Real-time availability & slot inventory

  • Availability is fetched at variant + date level via the Availabilities API — use this to show which dates have open slots before the user picks a time
  • Slot-level inventory (exact seat/pax counts per time slot) is fetched via the Inventory API
  • Both APIs must always be called in real time — never cache or reuse availability or inventory responses
  • Inventory is time-slot based and highly dynamic — slots can sell out or open up between the user browsing and completing checkout

Pax types

  • Pax types are defined at the time slot level — they can vary between slots for the same variant, since Headout aggregates multiple suppliers on the backend
  • Never hardcode pax type assumptions — always render them dynamically from the API response
  • Common examples: Adult, Child, EU Adult, Non-EU Adult — but the actual set varies per slot
  • See Pax Types for the full reference list

Pricing

Pricing surfaces at three levels in the API. Use the right one for the right job — they are not interchangeable:
SourceAPIWhat the price represents
Product-level pricingList Products / Get ProductMinimum across all variants and all their inventories — use as the “from” price on listing cards
Variant-level pricingGet Product (inside each variant)Minimum across all inventory slots for that variant — use as the starting price on the variant selection screen
Availabilities pricingAvailabilities APIMinimum selling price at a date level for that variant — use for date picker display
Inventory pricingInventory APIExact slot-level price — use this and only this for checkout totals and booking validation
Fields inside pricing:
  • currency — currency code for the returned price
  • profileTypePER_PERSON or PER_GROUP
  • headoutSellingPrice — minimum Headout selling price (MSP) — partners must not sell below this
  • netPrice — partner net price (API Partner accounts)
  • commissionAmount — commission amount (Affiliate accounts)
“From” / starting price. The product-level pricing is the minimum bookable price across all variants and time slots for that product. A product with a single variant can still show different starting prices on different dates because slot-level and supplier-backed inventory varies — treat the starting price as the lowest currently-known starting point, not a fixed quote. Deprecated: listingPrice. The older listingPrice object (with minimumPrice, bestDiscount, etc.) is deprecated. It is still returned for backward compatibility but should not be used in new integrations — read pricing instead.

Guest details & dynamic input fields

Some variants require additional guest information beyond name/email/phone.

Input fields

Every booking request requires input fields — these are the data fields collected per customer as part of the booking. They can include standard fields like name, email, and phone, or custom fields like passport number, nationality, meal preference, age, weight, height, and many more. Headout supports 200+ input field types, but all of them map to one of 6 data types:
Data typeDescription
BooleanTrue / false selection
StringFree text input
IntegerNumeric input
EnumSelection from a predefined list of values
LocationLocation input — see handling rules below
DateDate input
Critical: Location field handling The Location data type has two distinct behaviors depending on whether the field includes a predefined values list:
  • If a values list is present → the field only accepts one of the provided value object IDs as input. Render it as a dropdown and pass the selected ID.
  • If no values list is present → the field accepts any free-text string as input. Render it as an open text field.
Input fields are defined dynamically per variant in the Product Details API. Form rendering must be fully driven by the API response — never hardcode field assumptions. See Input Fields for the full reference. Each input field specifies the level at which data is collected:
LevelWhat it means
PRIMARY_CUSTOMERField required only for the primary customer
ALL_CUSTOMERField required for every customer in the booking

Guest objects

  • A guest object is required for every pax booked, regardless of whether input fields are needed for that pax
  • The level field on each input field determines which guests need that field populated
  • For a guest where no input fields are required (e.g. input fields are PRIMARY_CUSTOMER only and this is guest 2, 3, etc.) — you must still send a guest object with:
    • inputFields array set to empty []
    • paxType populated
    • isPrimaryCustomer set to false
⚠️ Every pax must have a corresponding guest object in the booking request. An empty inputFields array is valid and expected for non-primary guests when fields are not required for them. Never omit the guest object entirely.

Booking lifecycle & statuses

A booking moves through a sequence of statuses, not a single “is it done yet” flag. Each status answers a different question — is it captured?, is the supplier holding the reservation?, is the ticket ready? — and the legal next steps depend on the current status.

Statuses

StatusMeaning
UNCAPTUREDBooking entry created but payment not yet captured. Does not lock price or inventory.
PENDINGPayment captured. Booking is confirmed with the supplier — show as confirmed to the customer. Ticket generation may still be in progress.
COMPLETEDTicket generated and delivered. Available in the tickets array.
CANCELLEDBooking has been cancelled. Can be reached from PENDING or COMPLETED.
FAILEDCapture was attempted but rejected. The booking cannot move to any other status.
CAPTURE_TIMEDOUTUNCAPTURED booking was not captured within 1 hour and can no longer be captured. The booking cannot move to any other status.

Transitions

From UNCAPTURED (after Create Booking), one of the following happens:
  • Remains UNCAPTURED until captured (no inventory or price lock)
  • PENDING when capture succeeds
  • FAILED when capture is attempted but rejected by Headout or the supplier
  • CAPTURE_TIMEDOUT when no capture is attempted within 1 hour
From PENDING:
  • COMPLETED when the ticket is generated (instant for hasInstantConfirmation: true, usually within ~30 min otherwise, p99 up to 1 day before the experience)
  • CANCELLED if the booking is cancelled before fulfilment
From COMPLETED:
  • CANCELLED if the booking is cancelled after the ticket has been generated (e.g. customer-initiated cancellation within policy, or a venue closure)
From FAILED or CAPTURE_TIMEDOUT: no further transitions. Create a new booking if the customer still wants to proceed.

Key notes

  • PENDING is confirmed. It means payment is captured and the supplier is holding the reservation. Treat it as a confirmed booking in your UI; ticket generation is a separate, often-delayed step.
  • COMPLETED is not the immediate next state after UNCAPTURED. Capture moves a booking to PENDING first; COMPLETED follows when the ticket is generated.
  • PENDING and COMPLETED can still move to CANCELLED — including Headout-initiated cancellations like venue closures.
  • UNCAPTURED is never sent via webhook. Other status transitions are.

Ticket generation & hasInstantConfirmation

Each product includes a hasInstantConfirmation flag:
ValueMeaning
trueTicket generated immediately
falseTicket generated with delay
Typical timelines:
  • Instant confirmation: < 1 minute (avg)
  • Delayed generation: ~30 minutes on average, p99 up to 1 day before experience for example, some venues like Louvre release tickets only 1 day before the experience date
For ticket generation delayed products:
  • Booking should still be shown as confirmed as soon as status reaches PENDING or beyond
  • Ticket generation is asynchronous
  • Voucher updates automatically when the ticket is ready

Voucher URL & ticket delivery

Voucher URL — key points

  • Acts as the single source of truth
  • Shows booking status, ticket state, and experience instructions
  • Can be Headout-branded or re-skinned by the partner by masking out the Headout logo and contact details
  • Guides users clearly for delayed ticket generation
The voucher URL should be treated as the authoritative post-booking artifact. It reflects the latest booking and ticket state, even when tickets are generated later or booking status changes. Voucher messaging automatically adapts for delayed tickets.

Default customer communication

By default, Headout sends customer-facing emails directly to the booking’s primary customer using Headout branding — booking confirmation, voucher link, and ticket delivery notifications. If you have your own customer communication flow ready and want Headout to stop sending these emails, this can be disabled on a per-partner basis. Contact your Headout SPOC to opt out. Do not flip this off until your own emails (or other channels) are wired up and tested end-to-end — once opt-out is active, customers will not receive any communication from Headout, so the entire ticket-handoff is your responsibility.

Ticket types

How you need to handle ticket types depends entirely on which voucher flow you have implemented:
  • Using the Headout voucher URL directly — no additional handling needed. All ticket types are rendered correctly out of the box.
  • Embedding the Headout voucher in an iframe — no additional handling needed. The voucher renders correctly inside your UI.
  • Taking a screenshot of the Headout voucher to generate your own branded PDF — ⚠️ you must handle this carefully. For PDF_URL and HTML_URL ticket types, the Headout voucher renders a download button rather than the ticket inline. A screenshot will only capture the button, not the ticket. You must extract the URL from the API response and handle the download and rendering yourself.
Tickets are returned in the booking response under tickets[] once status reaches COMPLETED. Each ticket object includes a type field:
TypeURL presentDescription
QRCODENoQR code rendered inline on the voucher
BARCODENoBarcode rendered inline on the voucher
TEXTNoPlain text ticket code on the voucher
PDF_URLYesLink to downloadable PDF ticket
HTML_URLYesLink to hosted HTML ticket page

Sandbox vs production behavior

Sandbox environment

Only a limited set of products transition to COMPLETED automatically. See Fulfilment on Sandbox for the full list.
  • All other sandbox bookings may remain in PENDING
  • Sandbox should be used to validate: booking flow, webhooks, voucher rendering, and status transitions

Production environment

  • Real supplier behavior applies
  • Ticket generation follows hasInstantConfirmation
  • Cancellation and reschedule rules are enforced strictly

Webhooks & booking updates

Webhooks are essential to:
  • Track ticket generation
  • Receive cancellation or reschedule updates
  • Handle failures
  • Keep booking state in sync
Partners must assume:
  • Status transitions are non-linear
  • Completed bookings can still be cancelled (ex: in case of venue closures etc)

Verifying webhook authenticity

Headout does not yet sign webhook payloads. The supported workaround is IP whitelisting — accept incoming webhook traffic only from Headout’s known source IPs. Contact your Headout SPOC for the current IP list. Signature-based verification is in progress; see Upcoming releases.