> ## Documentation Index
> Fetch the complete documentation index at: https://partner.headout.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Voucher API deep dive

> A section-by-section walkthrough of the partner voucher response — what each part holds, when it is null, and how to render it.

This guide walks through every section of the [Get a voucher](https://partner.headout.com/docs/api-partner/v2/vouchers/get.md) response. Each section shows the JSON it returns, followed by what the fields mean and when they are absent.

Several sections carry a **See it on a voucher** example, pairing the JSON with the matching part of the Headout voucher. They all come from one booking, so they fit together.

## Response at a glance

| Section | What it holds | Null when |
| - | - | - |
| `bookingStatus` | Lifecycle state of the booking | Never |
| `voucherTemplate` | Layout to render the voucher in | Never |
| `header` | Booking and product identifiers | Never |
| `callouts` | Information banners to display | Never — returned empty instead |
| `bookingDetails` | Guests, schedule, seats, pickup | No booking details available |
| `checkinButton` | Online check-in link | Experience has no online check-in, or booking cancelled |
| `ticketSection` | Tickets and QR codes | No tickets attached yet, or booking cancelled |
| `instructions` | Redemption instructions | Experience has no instructions |
| `partnerDetails` | Operator contact details | Operator supplied none |
| `disclaimer` | Legal notice for the voucher footer | Nothing to disclaim |

***

## Booking status

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "COMPLETED",
  "voucherTemplate": "SINGLE_PAGE"
}
```

`bookingStatus` is the first thing to check. It uses the same vocabulary as [Get Booking](https://partner.headout.com/docs/api-partner/v2/bookings/get.md), so the voucher and the booking endpoints never disagree:

* `PENDING` — payment captured and confirmed with the supplier
* `COMPLETED` — booking fulfilled
* `CANCELLED` — booking cancelled

Render tickets whenever `ticketSection` is present rather than gating on the status.

A booking that was never captured has no voucher at all: `UNCAPTURED` and `CAPTURE_TIMEDOUT` bookings return **`404`** rather than a payload, and there is nothing to retry.

`voucherTemplate` tells you which layout to render the voucher in — `SINGLE_PAGE` for a single screen, `MULTI_PAGE` for a longer multi-section layout.

> [!WARNING]
>
> Render the voucher in the template returned. Venue staff check vouchers against the layout they expect for that experience, so a voucher rendered in the other template risks the guest being turned away at entry.

***

## Header

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"header": {
  "bookingId": 126890,
  "voucherId": 415872,
  "displayBookingId": "HO-126890",
  "product": { "productId": 18969, "name": "Colosseum Tour" },
  "variant": { "variantId": 25525, "name": "Guided — Small Group" },
  "vendorLogoUrl": "https://cdn.headout.com/vendor/logos/opera-tours.png"
}
```

| Field | Description |
| - | - |
| `bookingId` | The same value as `bookingId` on [Get Booking](https://partner.headout.com/docs/api-partner/v2/bookings/get.md) |
| `voucherId` | Matches the ID you passed in the request URL |
| `displayBookingId` | Booking reference to show the guest. If absent, display `voucherId` instead |
| `product` | The experience that was booked, with its Headout `productId` |
| `variant` | The tour option that was booked |
| `vendorLogoUrl` | Vendor logo to show on the voucher |

Show `displayBookingId` as the booking reference on the voucher. Should it ever be absent, display `voucherId` in its place, so the guest always sees a reference.

`vendorLogoUrl` is `null` when the vendor does not want their logo on the voucher — render it without a logo in that case, rather than substituting your own or a placeholder.

> **See it on a voucher**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> "header": {
>   "bookingId": 28190019,
>   "voucherId": 32854720,
>   "displayBookingId": "HEA328547200",
>   "product": {
>     "productId": 10209,
>     "name": "1-Day Ticket to Disneyland® Paris"
>   },
>   "variant": {
>     "variantId": 18862,
>     "name": "2 Disney® Parks Ticket"
>   },
>   "vendorLogoUrl": "https://cdn-imgix-open.headout.com/voucher/at-the-top-03.jpg"
> }
> ```
>
> ![Voucher header showing the booking reference, product name, selected variant and the vendor logo](https://mintcdn.com/headout-a44a3f3d/DixgfdkJj8DwFryF/assets/voucher-header.png?fit=max\&auto=format\&n=DixgfdkJj8DwFryF\&q=85\&s=997096c5e2f68a70e6adf49fb9f0965a)
>
> The same fields on the Headout voucher
>
> `displayBookingId` is the reference above the title, `product.name` the title itself, `variant.name` the "Selected option" line, and `vendorLogoUrl` the logo on the right.

***

## Callouts

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"callouts": [
  {
    "title": "Important information",
    "htmlDescription": "<p>Meet your host at the designated meeting point. Do check the location instructions to get there.</p>"
  }
]
```

An ordered array of information banners to display on the voucher. Render every entry in the order returned, showing `title` as a heading and `htmlDescription` as its body — the HTML is pre-sanitized and can be rendered directly.

The array is returned empty when a booking has no callouts.

***

## Booking details

`bookingDetails` carries the guests, schedule, seats, and pickup for the booking. It may be `null`. When present, it contains the sections below.

### Guests

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"customerName": "Jane Smith",
"paxSummary": {
  "summary": "2 Adults, 1 Child",
  "details": [
    { "paxType": "ADULT", "displayName": "Adult", "count": 2, "totalPrice": null },
    { "paxType": "CHILD", "displayName": "Child", "count": 1, "totalPrice": null }
  ]
},
"guestFields": [
  {
    "guestNumber": 1,
    "name": "Jane Smith",
    "email": "jane.smith@example.com",
    "phone": "+393331234567",
    "customFields": null
  }
]
```

`customerName` holds the primary guest's name as entered at checkout.

`paxSummary` gives a ready-to-render `summary` plus one `details` entry per pax type. The whole object may be `null` when no guest breakdown is available for the booking.

`guestFields` holds per-guest form data collected at checkout — `guestNumber` (1-indexed) plus optional `name`, `email`, `phone`, and `customFields` for experience-specific questions such as dietary preference or t-shirt size. It is `null` for experiences that do not collect per-guest data, and individual fields within an entry may still be `null`.

### Schedule

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"schedule": {
  "openDated": false,
  "experienceDate": "2026-06-15",
  "voucherValidUntil": null,
  "experienceStartDateTime": "2026-06-15T09:00:00",
  "experienceEndDateTime": "2026-06-15T12:00:00",
  "durationMinutes": 180,
  "inventoryType": "FIXED_START_FIXED_DURATION"
}
```

`openDated` and `inventoryType` are always present. The date and time fields are conditional:

| Field | Present when |
| - | - |
| `experienceDate` | The booking has a fixed date |
| `experienceStartDateTime` | `experienceDate` is set and the experience has a start time |
| `experienceEndDateTime` | `experienceDate` is set and the experience has an end time |
| `voucherValidUntil` | The voucher has a redemption deadline — the relevant expiry for open-dated bookings |
| `durationMinutes` | Experience duration is known |

All date-times are local to the experience, with no timezone offset. `inventoryType` tells you how the schedule is structured — see [Inventory types](https://partner.headout.com/docs/guide/enums-and-error-codes.md#inventory-types).

### Seats

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"seats": {
  "summary": "Stalls · Row F, Seats 11-12",
  "details": [
    {
      "sectionName": "Stalls",
      "seats": [
        { "row": "F", "seatNumber": "11", "seatCode": "STALLS-F-11", "description": null },
        { "row": "F", "seatNumber": "12", "seatCode": "STALLS-F-12", "description": "Wheelchair accessible" }
      ]
    }
  ]
}
```

`seats` is `null` for non-seatmap bookings. When present it has a ready-to-render `summary` plus a `details` array broken down by section, then by seat.

### Tour properties

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"tourProperties": [
  { "type": "Language", "values": ["English"] }
]
```

The tour options selected at booking — language, group size, activity level, and so on. Each entry has a `type` naming the option and a `values[]` array holding the selection. The language property appears first when present. `null` when the booking has no properties.

### Pickup and drop-off

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"pickupDropoffLocation": {
  "address": "12 Rue de Rivoli, 75004 Paris, France",
  "directionsUrl": "https://www.google.com/maps/search/?api=1&query=48.8558,2.3588",
  "coordinates": { "latitude": 48.8558, "longitude": 2.3588 },
  "pickupTime": "You will be picked up between 08:30 - 09:00",
  "importantNotes": ["Wait in the hotel lobby, not outside"],
  "pickupDropOffType": "PICKUP_AND_DROPOFF",
  "dropoff": {
    "address": "Place du Trocadéro, 75116 Paris, France",
    "directionsUrl": "https://www.google.com/maps/search/?api=1&query=48.8619,2.2885",
    "coordinates": { "latitude": 48.8619, "longitude": 2.2885 },
    "importantNotes": null
  }
}
```

Where the guest is collected for this booking, and where they are dropped off. It is `null` when the booking has no pickup — which is most bookings, since a pickup is only collected for transfers and door-to-door experiences.

A meeting point is not returned here. Meeting points belong to the experience rather than the booking, and appear under [`instructions`](#instructions) instead.

| Field | Description |
| - | - |
| `address` | Free-text address or description. Null when not available. |
| `directionsUrl` | Google Maps link. Null when no coordinates are available. |
| `coordinates` | `{ latitude, longitude }` — null when coordinates are not available |
| `pickupTime` | Ready-to-render pickup sentence (e.g. `"You will be picked up between 08:30 - 09:00"`). Null when no pickup timing is configured. |
| `importantNotes` | Array of pickup notes. Null when none. |
| `pickupDropOffType` | For transfers, whether a drop-off is included. Null when the experience is not a transfer. |
| `dropoff` | Where the guest is dropped off, in the same shape as the fields above. Null when there is no drop-off. |

For a transfer, `pickupDropOffType` tells you what the booking covers:

* `PICKUP` — pickup only, no drop-off. `dropoff` is null.
* `PICKUP_AND_DROPOFF` — both, at different places. `dropoff` carries the drop-off.
* `PICKUP_SAME_AS_DROPOFF` — the guest is returned to the pickup point.

`dropoff` mirrors the pickup fields — `address`, `directionsUrl`, `coordinates` and `importantNotes` — so you can render it with the same component.

***

## Instructions

`instructions` is `null` when the experience has no redemption instructions. When present, **exactly one** of `legacy` or `structured` is non-null — never both.

```js theme={"theme":{"light":"github-light","dark":"github-dark"}}
if (instructions.legacy != null) {
  // Render legacy.htmlContent, and legacy.location if present
} else if (instructions.structured != null) {
  // Render the structured sections below
}
```

### Legacy instructions

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"instructions": {
  "legacy": {
    "htmlContent": "<h3>Before you go</h3><p>Bring your passport and arrive 15 minutes early.</p>",
    "location": {
      "address": "Via del Colosseo, 00184 Roma RM, Italy",
      "directionsUrl": "https://www.google.com/maps/search/?api=1&query=41.8902,12.4924",
      "coordinates": { "latitude": 41.8902, "longitude": 12.4924 },
      "pickupTime": null,
      "importantNotes": null,
      "pickupDropOffType": null,
      "dropoff": null
    }
  },
  "structured": null
}
```

`legacy` is returned for experiences whose instructions are still authored by the operator as free-form HTML. It pairs that content with the meeting point it describes:

| Field | Description |
| - | - |
| `htmlContent` | The operator's instructions as an HTML fragment. Null when the experience has a meeting point but no written instructions. |
| `location` | The meeting point these instructions refer to, in the same shape as [`pickupDropoffLocation`](#pickup-and-drop-off). Null when the experience has no meeting point. The pickup-only fields are always null here. |

`htmlContent` is an HTML **fragment**, not a full document — headings, paragraphs, and lists with no wrapper element. Insert it into a container you control so it inherits your own typography; an iframe is not needed. It may include `<h3>` section headings, so style those to match your voucher.

```js theme={"theme":{"light":"github-light","dark":"github-dark"}}
// Plain DOM
document.querySelector("#voucher-instructions").innerHTML = voucher.instructions.legacy.htmlContent;
```

```jsx theme={"theme":{"light":"github-light","dark":"github-dark"}}
// React
<div
  className="voucher-instructions"
  dangerouslySetInnerHTML={{ __html: voucher.instructions.legacy.htmlContent }}
/>
```

> **See it on a voucher**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> "legacy": {
>   "htmlContent": "<div data-instruction-format=\"contentV2\">\r\n<h2><strong>HEADOUT | GALAXY CONNECT</strong></h2>\r\n\r\n<h3><strong>This is a ticket!</strong></h3>\r\n\r\n<ul>\r\n\t<li>\r\n\t<p>Go directly to the turnstiles at the entrance to the Resort.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>Please keep this ticket if you want to return to the Park on the same day or hop between both Parks if you have a ‘Hopper’ ticket.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>For the opening/closing times of the Resort, <a href=\"https://www.disneylandparis.com/en-usd/\">visit www.disneylandparis.com</a>.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>The Disney® Parks are non smoking. This rule also applies to electronic cigarettes. Please check the Disneyland Paris App or the Guide to the 2 Disney® Parks to find the smoking areas.</p>\r\n\t</li>\r\n</ul>\r\n\r\n<p> </p>\r\n\r\n<h3><strong>Conditions for use:</strong></h3>\r\n\r\n<ul>\r\n\t<li>\r\n\t<p>Your e-ticket is Mobile enabled or can be printed, on white A4 paper and vertical format.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>Please ensure that the printing quality is correct. If in doubt, please reprint your ticket.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>This ticket is cancellable up to 3 days before your visit.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>This ticket is personal and non-transferable. When you use it, you may be asked to present identification with a photo in the same name. To prevent fraudulent re-entry, your photograph will be taken and associated with your adult entry ticket for the purpose of checking guest access to the Disney Parks. </p>\r\n\t</li>\r\n\t<li>\r\n\t<p>If any of the rules indicated above are not respected, this ticket will be considered invalid.</p>\r\n\t</li>\r\n\t<li>The timings mentioned on the e-ticket are in French local time (CET). Also, please expect longer queues and wait times during peak times.</li>\r\n</ul>\r\n</div><h3>Policies</h3>You can cancel for free until 09:30 AM on 23 August, 2026.",
>   "location": {
>     "address": "Disneyland Paris, Boulevard de Parc, Coupvray, France",
>     "directionsUrl": "https://www.google.com/maps/search/?api=1&query=48.8673858,2.783593",
>     "coordinates": {
>       "latitude": 48.8673858,
>       "longitude": 2.783593
>     },
>     "pickupTime": null,
>     "importantNotes": null,
>     "pickupDropOffType": null,
>     "dropoff": null
>   }
> }
> ```
>
> ![Voucher instructions and cancellation policy rendered from the HTML fragment](https://mintcdn.com/headout-a44a3f3d/DixgfdkJj8DwFryF/assets/voucher-instructions.png?fit=max\&auto=format\&n=DixgfdkJj8DwFryF\&q=85\&s=c5236bb38373d72ea9f25107dd33c075)
>
> htmlContent, rendered
>
> ![Voucher location block showing the meeting point address and a Directions link](https://mintcdn.com/headout-a44a3f3d/DixgfdkJj8DwFryF/assets/voucher-location.png?fit=max\&auto=format\&n=DixgfdkJj8DwFryF\&q=85\&s=eaf3b507c39ef15c570f419f55582d41)
>
> location, rendered
>
> One `legacy` object produces both blocks. `htmlContent` becomes the instructions and the cancellation policy — the trailing `<h3>Policies</h3>` is what splits them, which is why the fragment needs your heading styles. `location.address` becomes the location line and `directionsUrl` the "Directions" link.

### Structured instructions

`structured` has four sections, any of which can be `null`:

| Section | What it holds |
| - | - |
| `generalInstructions` | Late arrival policy, photo ID requirement, arrival guidance |
| `location` | Address groups for where to go |
| `additionalInfo` | Extra information supplied by the operator, as HTML |
| `policies` | Booking policies, one entry per policy |

The `title` on each section is a heading you can render as-is.

#### General instructions

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"generalInstructions": {
  "title": "General Instructions",
  "hasLateArrivalPolicy": false,
  "photoIdRequired": true,
  "reportingTimes": [
    {
      "label": "Arrive early",
      "value": "Don't miss a moment, arrive 15 minutes early to make the most out of your experience."
    }
  ]
}
```

Two flags you can use to surface warnings or badges:

* `hasLateArrivalPolicy` — when true, latecomers may be refused entry and are not eligible for a refund.
* `photoIdRequired` — when true, guests must bring a valid government-issued photo ID.

`reportingTimes[]` is a ready-to-render arrival prompt with a `label` and a fully formatted `value` sentence. It is `null` when no reporting time is configured.

#### Additional information and policies

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"additionalInfo": {
  "title": "Additional Information",
  "htmlContent": "<p>Comfortable walking shoes are recommended.</p>"
},
"policies": [
  {
    "type": "BOOKING_AMENDMENT",
    "value": "<p>Free cancellation up to 24 hours before the experience start time.</p>"
  }
]
```

`additionalInfo.htmlContent` is pre-sanitized HTML.

`policies` is a list with one entry per policy, each carrying a `type` and an HTML `value`. Today the only type is `BOOKING_AMENDMENT`, covering whether and until when the booking can be cancelled or rescheduled. Entries have no title of their own — render each under a heading you supply.

#### Location

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"location": {
  "title": "Where to go?",
  "heading": "Head to this location to start your experience",
  "addressSequenceType": "SINGLE_ADDRESS",
  "voucherExchangeLocationType": "VENUE_LOCATION",
  "addressGroups": [
    [
      {
        "badgeLabel": "Address details",
        "addressLine1": "Arch of Titus",
        "addressLine2": null,
        "city": "Rome",
        "country": "Italy",
        "zip": "00186",
        "landmark": "Near the Colosseum main entrance",
        "googleMapLink": "https://maps.google.com/?q=41.8902,12.4924",
        "latitude": 41.8902,
        "longitude": 12.4924,
        "hostDetails": "Look for your guide holding a green Opera Tours sign",
        "mediaLinks": null
      }
    ]
  ]
}
```

| Field | Description |
| - | - |
| `title` | Section title (e.g. `"Where to go?"`) |
| `heading` | Instruction sentence for the section — render as supporting copy under `title` |
| `addressSequenceType` | Controls the shape of `addressGroups` (see below). Nullable. |
| `voucherExchangeLocationType` | `VENUE_LOCATION` or `DIFF_LOCATION` — whether the voucher is exchanged at the activity venue or somewhere else. Applies to the section as a whole, not to individual addresses. Null when not set. |
| `addressGroups` | `Address[][]` — array of address arrays (see below) |

Every field on an address is nullable except `badgeLabel`:

| Field | Description |
| - | - |
| `badgeLabel` | Display label for this address, per the sequence type below |
| `addressLine1` / `addressLine2` | Street address lines |
| `city`, `country`, `zip` | Location components |
| `landmark` | Nearby landmark text (e.g. `"Near the fountain"`) |
| `googleMapLink` | Deep link to Google Maps |
| `latitude` / `longitude` | Coordinates for map rendering |
| `hostDetails` | Host identifier for meeting-point experiences (e.g. guide name, or the sign they hold) |
| `mediaLinks` | Photos or media of the location |

#### Address group shapes

`addressGroups` arrives ready to render, with each address carrying its own `badgeLabel`. Its shape depends on `addressSequenceType`:

> **SINGLE\_ADDRESS — independent options**
>
> All addresses are returned in a single flat group. The customer can choose any one of them — they are not sequential steps.
>
> **Badge labels:** `"Option 1"`, `"Option 2"`, …
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "addressSequenceType": "SINGLE_ADDRESS",
>   "addressGroups": [
>     [
>       { "badgeLabel": "Option 1", "addressLine1": "Times Square, New York" },
>       { "badgeLabel": "Option 2", "addressLine1": "Central Park South, New York" }
>     ]
>   ]
> }
> ```

> **ALL\_ADDRESS\_ANY\_ORDER — multiple addresses, any order**
>
> All addresses are returned in a single flat group. Every address is relevant, but they can be visited in any order.
>
> **Badge labels:** `"Location 1"`, `"Location 2"`, …
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "addressSequenceType": "ALL_ADDRESS_ANY_ORDER",
>   "addressGroups": [
>     [
>       { "badgeLabel": "Location 1", "addressLine1": "Pier 39, San Francisco" },
>       { "badgeLabel": "Location 2", "addressLine1": "Ferry Building, San Francisco" }
>     ]
>   ]
> }
> ```

> **ALL\_ADDRESS\_SPECIFIC\_ORDER — sequential multi-leg itinerary**
>
> Each group is one complete route through the experience (start → waypoints → end), returned longest-first. Render each group as a numbered step sequence.
>
> **Badge labels:** `"Start Location"` (first), `"End Location"` (last), `"Location N"` (middle).
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> {
>   "addressSequenceType": "ALL_ADDRESS_SPECIFIC_ORDER",
>   "addressGroups": [
>     [
>       { "badgeLabel": "Start Location", "addressLine1": "Hotel Zone, Cancún" },
>       { "badgeLabel": "Location 2", "addressLine1": "Marina dock, Puerto Morelos" },
>       { "badgeLabel": "End Location", "addressLine1": "Chichen Itza main gate" }
>     ]
>   ]
> }
> ```
>
> When `addressSequenceType` is `null`, the grouping is the same but every address carries the badge label `"Address details"`.

***

## Tickets

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"ticketSection": {
  "heading": "Your tickets",
  "subheading": "Download & show tickets at the venue",
  "tickets": [
    {
      "ticketType": "PDF_URL",
      "displayType": "PDF",
      "url": "https://www.example.com/example-voucher-1.pdf",
      "ticketCode": "TKT-9F21A",
      "ticketName": "Adult Ticket",
      "actionCta": "Download ticket Adult Ticket 1"
    }
  ]
}
```

Render every item in `tickets`. The list can hold more tickets than the booking has guests, and it can mix types, for example a `BARCODE` for entry and a `QRCODE` for an included audio guide on the same booking. Each one is needed at the venue, so do not show only the first, and do not assume one ticket per guest.

`ticketSection` is `null` when no tickets are attached to the booking. In that case the guest follows the redemption [`instructions`](#instructions). If the instructions include steps to generate or collect tickets, the guest must complete them. If they don't, no ticket is required and the guest presents the voucher at the venue. Omit the ticket section, and render the callouts and `instructions`. `ticketSection` is also `null` for a cancelled booking. See a live example of a voucher with no ticket section: [example voucher](https://www.sandbox-headout.com/voucher/1000003695/?secureBookingId=KniayC4xc5askqFYywK2TwRpDwHq7L53XorHacODZGnuyJOrzZ1pv7V3VN7JbqqZf06hTP3xzUD3MQid_TbP7kRCsjjqpfJBeBxlbqWQknc%3D\&source=internal).

`heading` and `subheading` are ready-to-render strings for the section. `subheading` is `null` when the section has no supporting line.

Each ticket carries `ticketType` (the underlying format) and `displayType` (how to render it). Branch on `displayType`:

| `displayType` | Typical `ticketType` | How to render |
| - | - | - |
| `PDF` | `PDF_URL` | Show a download button. `actionCta` has the button label, `url` is the download link. |
| `IMAGE` | `QRCODE`, `BARCODE` | Render `url` as a QR code or barcode image. |
| `TICKET_NUMBER` | `TEXT`, `HTML_URL` | Display `ticketCode` as a text confirmation code. For `HTML_URL`, `url` links to an HTML ticket view. |

`actionCta` carries the button label. It is returned only for `displayType: PDF` and is `null` otherwise.

> **See it on a voucher**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> "ticketSection": {
>   "heading": "Scan tickets",
>   "subheading": null,
>   "tickets": [
>     {
>       "ticketType": "QRCODE",
>       "displayType": "IMAGE",
>       "url": "https://www.example.com/example-qr-code-1.jpeg",
>       "ticketCode": "4013000000000000000000001",
>       "ticketName": null,
>       "actionCta": null
>     },
>     {
>       "ticketType": "QRCODE",
>       "displayType": "IMAGE",
>       "url": "https://www.example.com/example-qr-code-2.jpeg",
>       "ticketCode": "4013000000000000000000002",
>       "ticketName": null,
>       "actionCta": null
>     },
>     {
>       "ticketType": "QRCODE",
>       "displayType": "IMAGE",
>       "url": "https://www.example.com/example-qr-code-3.jpeg",
>       "ticketCode": "4013000000000000000000003",
>       "ticketName": null,
>       "actionCta": null
>     }
>   ]
> }
> ```
>
> ![Voucher ticket section headed Scan tickets, showing a QR code above its ticket code](https://mintcdn.com/headout-a44a3f3d/DixgfdkJj8DwFryF/assets/voucher-ticket-image.png?fit=max\&auto=format\&n=DixgfdkJj8DwFryF\&q=85\&s=98c21c0e1d1ff79b3a23e8019ebb69b3)
>
> The same fields on the Headout voucher
>
> `heading` is rendered as the section title, each ticket's `url` as the code image and `ticketCode` beneath it. The response holds all three tickets; this voucher is `MULTI_PAGE` with one ticket per page, so the page above shows `tickets[0]` — its code `4013000000000000000000001` is the one printed under the QR.

***

## Partner details

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"partnerDetails": {
  "vendorName": "XX Tours YY",
  "contactNumbers": ["+00 00 0000 0000"],
  "referenceNumbers": ["XXYY-0000-000000"]
}
```

The operator's contact details, `null` when the operator has not supplied any.

| Field | Description |
| - | - |
| `vendorName` | Name of the operator or vendor |
| `contactNumbers` | Phone numbers for the operator. Null when not provided. |
| `referenceNumbers` | Operator booking reference numbers. Null when not provided. |

> **See it on a voucher**
>
> ```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
> "partnerDetails": {
>   "vendorName": "Disneyland® Paris",
>   "contactNumbers": [
>     "03448 008 898"
>   ],
>   "referenceNumbers": [
>     "39040730"
>   ]
> }
> ```
>
> ![Voucher partner details showing the operator name, phone number and reference number](https://mintcdn.com/headout-a44a3f3d/DixgfdkJj8DwFryF/assets/voucher-partner-details.png?fit=max\&auto=format\&n=DixgfdkJj8DwFryF\&q=85\&s=313f83b7d199b1cc90a4471a53f6524c)
>
> The same fields on the Headout voucher
>
> `vendorName` and `contactNumbers` render under "Local partner details"; `referenceNumbers` as "Partner ref number".

***

## Check-in button

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"checkinButton": {
  "checkinUrl": "https://checkin.example.com/b/415872"
}
```

`checkinButton` is `null` for most bookings, and always `null` for a cancelled booking. When present, `checkinUrl` is a URL the customer can visit to check in to the experience.

***

## Disclaimer

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
"disclaimer": "Please carry a valid government-issued photo ID. Children under 6 enter free but must be accompanied by an adult."
```

A legal notice to display at the bottom of the voucher. Render it as-is when non-null.

***

## Examples

Five complete responses for the booking shapes you will see most often, each followed by the voucher it generates. These are real responses captured from the sandbox — only the operator's name, phone and reference numbers are masked, ticket URLs point at the CDN host, and the longest HTML fragments are trimmed with an inline marker.

**QR-code tickets**

An attraction entry with one QR code per guest — the most common ticketed shape. The guest scans each code at the gate.

**What to notice**

* Three guests, three tickets: `displayType: IMAGE`, so each `url` is rendered as the code image with its `ticketCode` printed beneath. `actionCta` is `null` — it only accompanies `displayType: PDF`.
* `vendorLogoUrl` is `null` — render the header without a logo.
* `instructions.structured` is set, so `legacy` is `null`. The venue address arrives as one `SINGLE_ADDRESS` group.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "COMPLETED",
  "voucherTemplate": "SINGLE_PAGE",
  "header": {
    "bookingId": 26174708,
    "voucherId": 30752272,
    "displayBookingId": "30752272",
    "product": {
      "productId": 37030,
      "name": "Alcatraz Tickets with Ferry Ride & Audio Guide"
    },
    "variant": {
      "variantId": 77352,
      "name": "Alcatraz Day Tour with On-Site Audio Guide"
    },
    "vendorLogoUrl": null
  },
  "callouts": [],
  "bookingDetails": {
    "purchaseDateTime": "2026-03-29T22:11:04Z",
    "customerName": "Guest 1",
    "paxSummary": {
      "summary": "1 Adult, 1 Youth, 1 Child",
      "details": [
        {
          "paxType": "ADULT",
          "displayName": "Adult",
          "count": 1,
          "totalPrice": null
        },
        {
          "paxType": "YOUTH",
          "displayName": "Youth",
          "count": 1,
          "totalPrice": null
        },
        {
          "paxType": "CHILD",
          "displayName": "Child",
          "count": 1,
          "totalPrice": null
        }
      ]
    },
    "guestFields": [
      {
        "guestNumber": 1,
        "name": "Guest 1",
        "email": "qa.voucher+30752272.1@example.com",
        "phone": "+910000000000",
        "customFields": null
      }
    ],
    "seats": null,
    "schedule": {
      "openDated": false,
      "experienceDate": "2026-03-30",
      "voucherValidUntil": null,
      "experienceStartDateTime": "2026-03-30T12:30:00Z",
      "experienceEndDateTime": "2026-03-30T18:00:00Z",
      "durationMinutes": null,
      "inventoryType": "FIXED_START_FLEXIBLE_DURATION"
    },
    "tourProperties": null,
    "pickupDropoffLocation": null
  },
  "checkinButton": null,
  "ticketSection": {
    "heading": "Scan tickets",
    "subheading": null,
    "tickets": [
      {
        "ticketType": "QRCODE",
        "displayType": "IMAGE",
        "url": "https://www.example.com/example-qr-code-1.jpeg",
        "ticketCode": "COB-EXAMPLE0-000000001-qE0000",
        "ticketName": null,
        "actionCta": null
      },
      {
        "ticketType": "QRCODE",
        "displayType": "IMAGE",
        "url": "https://www.example.com/example-qr-code-2.jpeg",
        "ticketCode": "COB-EXAMPLE0-000000002-qE0000",
        "ticketName": null,
        "actionCta": null
      },
      {
        "ticketType": "QRCODE",
        "displayType": "IMAGE",
        "url": "https://www.example.com/example-qr-code-3.jpeg",
        "ticketCode": "COB-EXAMPLE0-000000003-qE0000",
        "ticketName": null,
        "actionCta": null
      }
    ]
  },
  "instructions": {
    "legacy": null,
    "structured": {
      "generalInstructions": {
        "title": "General Instructions",
        "hasLateArrivalPolicy": true,
        "photoIdRequired": true,
        "reportingTimes": [
          {
            "label": "Arrive early",
            "value": "Don't miss a moment, arrive 15 minutes early to make the most out of your experience."
          }
        ]
      },
      "location": {
        "title": "Where to go?",
        "heading": "Head to this location to start your experience",
        "addressSequenceType": "SINGLE_ADDRESS",
        "voucherExchangeLocationType": null,
        "addressGroups": [
          [
            {
              "badgeLabel": "Address details",
              "addressLine1": "Alcatraz City Cruises",
              "addressLine2": "31 San Francisco Pier 33 - Alcatraz Island",
              "city": "San Francisco",
              "country": "US",
              "zip": "94124",
              "landmark": "",
              "googleMapLink": "https://maps.app.goo.gl/tCQua5y25Kujg79p9",
              "latitude": 37.806505,
              "longitude": -122.4071028,
              "hostDetails": null,
              "mediaLinks": []
            }
          ]
        ]
      },
      "additionalInfo": null,
      "policies": [
        {
          "type": "BOOKING_AMENDMENT",
          "value": "These tickets can't be cancelled or rescheduled."
        }
      ]
    }
  },
  "partnerDetails": {
    "vendorName": "XX Cruises YY",
    "contactNumbers": [
      "+0 (000) 000-0000"
    ],
    "referenceNumbers": [
      "XXYY-0000-000000"
    ]
  },
  "disclaimer": null
}
```

**The voucher it generates**

1. **Header** — reference `30752272` from `displayBookingId`, the product and variant names, no logo.
2. **Booking details** — "1 Adult, 1 Youth, 1 Child", the experience date, and a 12:30 entry with the venue open until 18:00 (`FIXED_START_FLEXIBLE_DURATION`: entry is timed, guests stay as long as they like).
3. **Scan tickets** — the section heading from `heading`, then three QR codes, each with its code text under it.
4. **Where to go?** — one address card for the ferry pier, with the map link, and the arrival prompt plus a late-arrival warning and photo-ID badge from `generalInstructions`.
5. **Policies** — the `BOOKING_AMENDMENT` entry rendered under a heading you supply.

**PDF tickets**

The same venue can instead attach downloadable PDFs — here two tickets for one booking, each a full ticket document.

**What to notice**

* `displayType: PDF`: render a download button per ticket, labelled from `actionCta`. `ticketCode` and `ticketName` are empty strings here — do not render them.
* `subheading` carries a supporting line for the ticket section.
* `additionalInfo` carries operator-authored HTML (trimmed below) — render it as-is inside your container.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "COMPLETED",
  "voucherTemplate": "SINGLE_PAGE",
  "header": {
    "bookingId": 26181286,
    "voucherId": 30759114,
    "displayBookingId": "30759114",
    "product": {
      "productId": 11899,
      "name": "Pena Palace & Park Tickets"
    },
    "variant": {
      "variantId": 22782,
      "name": "Pena Palace & Park Essential Ticket"
    },
    "vendorLogoUrl": ""
  },
  "callouts": [],
  "bookingDetails": {
    "purchaseDateTime": "2026-03-30T09:39:51Z",
    "customerName": "Guest 1",
    "paxSummary": {
      "summary": "2 Adults, 1 Child",
      "details": [
        {
          "paxType": "ADULT",
          "displayName": "Adult",
          "count": 2,
          "totalPrice": null
        },
        {
          "paxType": "CHILD",
          "displayName": "Child",
          "count": 1,
          "totalPrice": null
        }
      ]
    },
    "guestFields": [
      {
        "guestNumber": 1,
        "name": "Guest 1",
        "email": "qa.voucher+30759114.1@example.com",
        "phone": "+910000000000",
        "customFields": null
      }
    ],
    "seats": null,
    "schedule": {
      "openDated": false,
      "experienceDate": "2026-03-30",
      "voucherValidUntil": null,
      "experienceStartDateTime": "2026-03-30T14:30:00Z",
      "experienceEndDateTime": "2026-03-30T18:00:00Z",
      "durationMinutes": null,
      "inventoryType": "FIXED_START_FLEXIBLE_DURATION"
    },
    "tourProperties": null,
    "pickupDropoffLocation": null
  },
  "checkinButton": null,
  "ticketSection": {
    "heading": "Your ticket",
    "subheading": "Download & show tickets at the venue",
    "tickets": [
      {
        "ticketType": "PDF_URL",
        "displayType": "PDF",
        "url": "https://www.example.com/example-voucher-1.pdf",
        "ticketCode": "",
        "ticketName": "",
        "actionCta": "Download ticket 1"
      },
      {
        "ticketType": "PDF_URL",
        "displayType": "PDF",
        "url": "https://www.example.com/example-voucher-2.pdf",
        "ticketCode": "",
        "ticketName": "",
        "actionCta": "Download ticket 2"
      }
    ]
  },
  "instructions": {
    "legacy": null,
    "structured": {
      "generalInstructions": {
        "title": "General Instructions",
        "hasLateArrivalPolicy": true,
        "photoIdRequired": true,
        "reportingTimes": [
          {
            "label": "Arrive early",
            "value": "Don't miss a moment, arrive 15 minutes early to make the most out of your experience."
          }
        ]
      },
      "location": {
        "title": "Where to go?",
        "heading": "Head to this location to start your experience",
        "addressSequenceType": "SINGLE_ADDRESS",
        "voucherExchangeLocationType": null,
        "addressGroups": [
          [
            {
              "badgeLabel": "Address details",
              "addressLine1": "Estrada da Pena",
              "addressLine2": "",
              "city": "Sintra",
              "country": "PT",
              "zip": "2710-609",
              "landmark": "Park and National Palace of Pena",
              "googleMapLink": "https://maps.app.goo.gl/soufyzKxhJqKA7GL7",
              "latitude": 38.7879753,
              "longitude": -9.3902283,
              "hostDetails": null,
              "mediaLinks": []
            }
          ]
        ]
      },
      "additionalInfo": {
        "title": "Additional Information",
        "htmlContent": "<p dir=\"ltr\"><span style=\"white-space: pre-wrap;\">Download the link before your visit as internet  at the site may be limited. </span><a href=\"https://www.example.com/example-attachment.pdf\" target=\"_blank\" rel=\"noopener noreferrer\" dir=\"ltr\"><span style=\"white-space: pre-wrap;\">Click here</span></a></p><!-- trimmed for brevity -->"
      },
      "policies": [
        {
          "type": "BOOKING_AMENDMENT",
          "value": "These tickets can't be cancelled or rescheduled."
        }
      ]
    }
  },
  "partnerDetails": {
    "vendorName": "XX Palace Tours YY",
    "contactNumbers": null,
    "referenceNumbers": [
      "XXYY-0000-000000"
    ]
  },
  "disclaimer": null
}
```

**The voucher it generates**

1. **Header and booking details** — as in the previous example.
2. **Your ticket** — the `heading` and `subheading`, then two buttons: "Download ticket 1" and "Download ticket 2", each opening its `url`.
3. **Where to go?** — the palace address card with landmark and map link.
4. **Additional Information** — the operator's HTML fragment rendered in your typography.
5. **Policies** — the cancellation line under your own heading.

**No tickets — the voucher is the pass**

A booking with nothing to download or scan: `ticketSection` is `null` and the voucher itself is shown at the venue. Everything hangs on the header, schedule, and instructions.

**What to notice**

* `bookingStatus` is `PENDING` — payment captured and confirmed with the supplier; the voucher is already valid. Render tickets based on `ticketSection` presence, never on status.
* `ticketSection` is `null` while the booking is active — omit the section entirely; the voucher is the entry pass.
* `hasLateArrivalPolicy` and `photoIdRequired` are both `true` — surface both warnings.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "PENDING",
  "voucherTemplate": "SINGLE_PAGE",
  "header": {
    "bookingId": 28608560,
    "voucherId": 33289763,
    "displayBookingId": "33289763",
    "product": {
      "productId": 11727,
      "name": "Tokyo Tower Tickets"
    },
    "variant": {
      "variantId": 67884,
      "name": "Tokyo Tower Top Deck Ticket"
    },
    "vendorLogoUrl": ""
  },
  "callouts": [],
  "bookingDetails": {
    "purchaseDateTime": "2026-08-17T17:52:18Z",
    "customerName": "Alex Chen",
    "paxSummary": {
      "summary": "2 Adults",
      "details": [
        {
          "paxType": "ADULT",
          "displayName": "Adult",
          "count": 2,
          "totalPrice": null
        }
      ]
    },
    "guestFields": [
      {
        "guestNumber": 1,
        "name": "Alex Chen",
        "email": "alex.chen@example.com",
        "phone": "+818012345678",
        "customFields": null
      }
    ],
    "seats": null,
    "schedule": {
      "openDated": false,
      "experienceDate": "2026-08-18",
      "voucherValidUntil": null,
      "experienceStartDateTime": "2026-08-18T09:00:00Z",
      "experienceEndDateTime": "2026-08-18T23:00:00Z",
      "durationMinutes": null,
      "inventoryType": "FIXED_START_FLEXIBLE_DURATION"
    },
    "tourProperties": null,
    "pickupDropoffLocation": null
  },
  "checkinButton": null,
  "ticketSection": null,
  "instructions": {
    "legacy": null,
    "structured": {
      "generalInstructions": {
        "title": "General Instructions",
        "hasLateArrivalPolicy": true,
        "photoIdRequired": true,
        "reportingTimes": [
          {
            "label": "Arrive early",
            "value": "Don't miss a moment, arrive 15 minutes early to make the most out of your experience."
          }
        ]
      },
      "location": {
        "title": "Where to go?",
        "heading": "Head to this location to start your experience",
        "addressSequenceType": "SINGLE_ADDRESS",
        "voucherExchangeLocationType": null,
        "addressGroups": [
          [
            {
              "badgeLabel": "Address details",
              "addressLine1": "Tokyo Tower",
              "addressLine2": "4 Chome-2-8 Shibakoen, Minato City",
              "city": "Tokyo",
              "country": "JP",
              "zip": "105-0011",
              "landmark": "",
              "googleMapLink": "https://www.google.com/maps/search/?api=1&query=1&query_place_id=ChIJCewJkL2LGGAR3Qmk0vCTGkg",
              "latitude": 35.6585805,
              "longitude": 139.7454329,
              "hostDetails": null,
              "mediaLinks": []
            }
          ]
        ]
      },
      "additionalInfo": null,
      "policies": [
        {
          "type": "BOOKING_AMENDMENT",
          "value": "These tickets can't be cancelled or rescheduled."
        }
      ]
    }
  },
  "partnerDetails": {
    "vendorName": "XX Tours YY",
    "contactNumbers": null,
    "referenceNumbers": null
  },
  "disclaimer": null
}
```

**The voucher it generates**

1. **Header** — reference `33289763`, product and variant names.
2. **Booking details** — the primary guest from `guestFields`, "2 Adults", and the entry window from the schedule.
3. **No ticket section** — nothing to download; the rendered voucher is what venue staff check.
4. **Where to go?** — the tower's address card with the Google Maps deep link, plus the arrive-early prompt, late-arrival warning, and photo-ID badge.
5. **Policies** — the non-refundable line.

**Cancelled booking**

The same voucher URL keeps working after cancellation, but the payload changes: everything that grants entry disappears.

**What to notice**

* `bookingStatus` is `CANCELLED`; `ticketSection` and `checkinButton` are `null` — always, for a cancelled booking.
* The header, booking details, and instructions remain, so the guest can still see what was cancelled.
* Bookings that were never captured return `404` instead — this shape only appears for bookings that existed and were then cancelled.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "CANCELLED",
  "voucherTemplate": "SINGLE_PAGE",
  "header": {
    "bookingId": 26181033,
    "voucherId": 30758852,
    "displayBookingId": "30758852",
    "product": {
      "productId": 11899,
      "name": "Pena Palace & Park Tickets"
    },
    "variant": {
      "variantId": 22782,
      "name": "Pena Palace & Park Essential Ticket"
    },
    "vendorLogoUrl": null
  },
  "callouts": [],
  "bookingDetails": {
    "purchaseDateTime": "2026-03-30T09:27:37Z",
    "customerName": "Guest 1",
    "paxSummary": {
      "summary": "2 Adults",
      "details": [
        {
          "paxType": "ADULT",
          "displayName": "Adult",
          "count": 2,
          "totalPrice": null
        }
      ]
    },
    "guestFields": [
      {
        "guestNumber": 1,
        "name": "Guest 1",
        "email": "qa.voucher+30758852.1@example.com",
        "phone": "+910000000000",
        "customFields": null
      }
    ],
    "seats": null,
    "schedule": {
      "openDated": false,
      "experienceDate": "2026-03-30",
      "voucherValidUntil": null,
      "experienceStartDateTime": "2026-03-30T14:00:00Z",
      "experienceEndDateTime": "2026-03-30T18:00:00Z",
      "durationMinutes": null,
      "inventoryType": "FIXED_START_FLEXIBLE_DURATION"
    },
    "tourProperties": null,
    "pickupDropoffLocation": null
  },
  "checkinButton": null,
  "ticketSection": null,
  "instructions": {
    "legacy": null,
    "structured": {
      "generalInstructions": {
        "title": "General Instructions",
        "hasLateArrivalPolicy": true,
        "photoIdRequired": false,
        "reportingTimes": [
          {
            "label": "Arrive early",
            "value": "Don't miss a moment, arrive 15 minutes early to make the most out of your experience."
          }
        ]
      },
      "location": {
        "title": "Where to go?",
        "heading": "Head to this location to start your experience",
        "addressSequenceType": "SINGLE_ADDRESS",
        "voucherExchangeLocationType": null,
        "addressGroups": [
          [
            {
              "badgeLabel": "Address details",
              "addressLine1": "National Palace of Pena",
              "addressLine2": "Estrada da Pena",
              "city": "Sintra",
              "country": "PT",
              "zip": "2710-609",
              "landmark": "",
              "googleMapLink": "https://maps.app.goo.gl/fAxBc2f4sunXQioMA",
              "latitude": 38.7874492,
              "longitude": -9.390643,
              "hostDetails": null,
              "mediaLinks": []
            }
          ]
        ]
      },
      "additionalInfo": {
        "title": "Additional Information",
        "htmlContent": "<p dir=\"ltr\"><b><strong style=\"white-space: pre-wrap;\">Your Complimentary Guidebook</strong></b></p><!-- trimmed for brevity -->"
      },
      "policies": [
        {
          "type": "BOOKING_AMENDMENT",
          "value": "These tickets can't be cancelled or rescheduled."
        }
      ]
    }
  },
  "partnerDetails": {
    "vendorName": "XX Palace Tours YY",
    "contactNumbers": null,
    "referenceNumbers": null
  },
  "disclaimer": null
}
```

**The voucher it generates**

1. **A cancelled state, not a pass** — render a clear cancelled banner from `bookingStatus` at the top. The voucher must not look redeemable.
2. **Reference information only** — header and booking details stay visible so the guest can identify which booking was cancelled and for when.
3. **Nothing actionable** — no tickets and no check-in button.

**Disney multi-page**

A Disneyland® Paris booking for three guests. The response is the same contract as every other example — what changes is `voucherTemplate`, which asks you to lay the voucher out as one page per ticket instead of one continuous page.

**What to notice**

* `voucherTemplate` is `MULTI_PAGE`. Nothing else in the payload is split per page — you receive one response and decide the pagination yourself, one page per entry in `ticketSection.tickets`.
* `displayBookingId` is `"HEA1000003194"`, not a bare number. Disney bookings fall back to a `HEA`-prefixed id when the operator has not returned its own reference yet. Render `displayBookingId` verbatim; never reconstruct it from `bookingId`.
* `instructions.legacy` is set and `instructions.structured` is `null` — the opposite of the other examples. Operators still on HTML instructions arrive this way, so branch on which of the two is non-null rather than assuming `structured`.
* `disclaimer` is non-null and long. Multi-page vouchers repeat it on every page, because each page travels separately once printed.
* Three `PDF` tickets, one per guest, with `actionCta` numbered `Download ticket 1`…`3`. `ticketName` is `null`, so the CTA carries the numbering on its own.

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "bookingStatus": "COMPLETED",
  "voucherTemplate": "MULTI_PAGE",
  "header": {
    "bookingId": 1000003197,
    "voucherId": 1000003194,
    "displayBookingId": "HEA1000003194",
    "product": {
      "productId": 10209,
      "name": "1-Day Ticket to Disneyland® Paris"
    },
    "variant": {
      "variantId": 18859,
      "name": "1 Disney® Park Ticket"
    },
    "vendorLogoUrl": null
  },
  "callouts": [],
  "bookingDetails": {
    "purchaseDateTime": "2026-08-24T16:25:30Z",
    "customerName": "Alex Chen",
    "paxSummary": {
      "summary": "3 Adults",
      "details": [
        {
          "paxType": "ADULT",
          "displayName": "Adult",
          "count": 3,
          "totalPrice": null
        }
      ]
    },
    "guestFields": [
      {
        "guestNumber": 1,
        "name": "Alex Chen",
        "email": "docs.capture@example.com",
        "phone": "+33123456780",
        "customFields": null
      },
      {
        "guestNumber": 2,
        "name": "Sam Rivera",
        "email": "docs.capture@example.com",
        "phone": "+33123456781",
        "customFields": null
      },
      {
        "guestNumber": 3,
        "name": "Jordan Blake",
        "email": "docs.capture@example.com",
        "phone": "+33123456782",
        "customFields": null
      }
    ],
    "seats": null,
    "schedule": {
      "openDated": false,
      "experienceDate": "2026-09-07",
      "voucherValidUntil": null,
      "experienceStartDateTime": "2026-09-07T09:30:00Z",
      "experienceEndDateTime": "2026-09-07T21:00:00Z",
      "durationMinutes": null,
      "inventoryType": "FLEXIBLE_START_FLEXIBLE_DURATION"
    },
    "tourProperties": null,
    "pickupDropoffLocation": null
  },
  "checkinButton": null,
  "ticketSection": {
    "heading": "Your ticket",
    "subheading": "Download & show tickets at the venue",
    "tickets": [
      {
        "ticketType": "PDF_URL",
        "displayType": "PDF",
        "url": "https://www.example.com/example-voucher-1.pdf",
        "ticketCode": "4013000000000000000000001",
        "ticketName": null,
        "actionCta": "Download ticket 1"
      },
      {
        "ticketType": "PDF_URL",
        "displayType": "PDF",
        "url": "https://www.example.com/example-voucher-2.pdf",
        "ticketCode": "4013000000000000000000002",
        "ticketName": null,
        "actionCta": "Download ticket 2"
      },
      {
        "ticketType": "PDF_URL",
        "displayType": "PDF",
        "url": "https://www.example.com/example-voucher-3.pdf",
        "ticketCode": "4013000000000000000000003",
        "ticketName": null,
        "actionCta": "Download ticket 3"
      }
    ]
  },
  "instructions": {
    "legacy": {
      "htmlContent": "<div data-instruction-format=\"contentV2\">\r\n<h2><strong>HEADOUT | GALAXY CONNECT</strong></h2>\r\n\r\n<h3><strong>This is a ticket!</strong></h3>\r\n\r\n<ul>\r\n\t<li>\r\n\t<p>Go directly to the turnstiles at the entrance to the Resort.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>Please keep this ticket if you want to return to the Park on the same day or hop between both Parks if you have a ‘Hopper’ ticket.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>For the opening/closing times of the Resort, <a href=\"https://www.disneylandparis.com/en-usd/\">visit www.disneylandparis.com</a>.</p>\r\n\t</li>\r\n\t<li>\r\n\t<p>The Disney® Parks are non smoking. This rule also applies to electronic cigarettes. Please check the Disneyland Paris App or the Guide to the 2 Disney® Parks to find the smoking areas.</p>\r\n\t</li>\r\n</ul><!-- trimmed for brevity -->",
      "location": {
        "address": "Disneyland Paris, Boulevard de Parc, Coupvray, France",
        "directionsUrl": "https://www.google.com/maps/search/?api=1&query=48.8673858,2.783593",
        "coordinates": {
          "latitude": 48.8673858,
          "longitude": 2.783593
        },
        "pickupTime": null,
        "importantNotes": null,
        "pickupDropOffType": null,
        "dropoff": null
      }
    },
    "structured": null
  },
  "partnerDetails": {
    "vendorName": "Disneyland® Paris",
    "contactNumbers": null,
    "referenceNumbers": null
  },
  "disclaimer": "This ticket gives one person entry to the park(s) or the event indicated above.  It is only valid for the indicated date(s). <!-- trimmed for brevity -->"
}
```

> **How a multi-page voucher looks**
>
> Each ticket becomes its own page, and every page is a complete pass on its own — badge, booking reference, product, location, one ticket, instructions and disclaimer. A guest can hand one page to each member of the party and nothing on it is missing.
>
> ![Three pages of a Disneyland Paris voucher side by side, each labelled Ticket 1 of 3, Ticket 2 of 3 and Ticket 3 of 3, with identical header, booking details, instructions and disclaimer](https://mintcdn.com/headout-a44a3f3d/cSKm5jlfvwfbUVG5/assets/voucher-multipage-pages.png?fit=max\&auto=format\&n=cSKm5jlfvwfbUVG5\&q=85\&s=68f8ff748924452ed79904ffd38b68f5)
>
> The same booking as three pages — only the ticket badge and the ticket itself differ
>
> A single page in full:
>
> ![A single page of the multi-page voucher, from the Ticket 1 of 3 badge through booking details, the download button, instructions, cancellation policy, partner details and disclaimer](https://mintcdn.com/headout-a44a3f3d/cSKm5jlfvwfbUVG5/assets/voucher-multipage-page.png?fit=max\&auto=format\&n=cSKm5jlfvwfbUVG5\&q=85\&s=42111490937b0f4dfefd32ca733c2568)
>
> Page one — a complete pass for one guest
>
> Two things to copy from this rendering:
>
> * **Number the pages.** Each one carries a `Ticket N of 3` badge, so a guest holding one page knows how many exist. The payload gives you the count as `ticketSection.tickets.length`.
> * **Split the party across the pages.** The Headout voucher shows `1 Adult` and that guest's share of the price on each page, not the whole party. The API hands you the full `paxSummary` (`"3 Adults"`) once, so divide it yourself if you want to match — or keep the whole summary on every page if your venue prefers it.
>
> Compare with `SINGLE_PAGE`, where the same three tickets stack inside one ticket section on a single page and the header, instructions, and disclaimer appear once.

**The voucher it generates**

1. **Three pages, one per ticket** — driven by `voucherTemplate: MULTI_PAGE` and the length of `ticketSection.tickets`, each badged `Ticket N of 3`.
2. **Header on every page** — product and variant names, and `displayBookingId` as `HEA1000003194` so venue staff can identify the booking from any single page.
3. **Booking details on every page** — the party from `paxSummary` and the 09:30–21:00 window from the schedule. `inventoryType` is `FLEXIBLE_START_FLEXIBLE_DURATION`, so the times bound the park's opening hours rather than a timed entry. The Headout voucher splits the party and shows one guest per page; the payload gives you the whole summary and leaves that choice to you.
4. **One ticket per page** — the `heading` and `subheading` from `ticketSection`, a single download button labelled from that page's `actionCta`, and its `ticketCode` printed beneath.
5. **Instructions from `legacy.htmlContent`** — rendered as-is inside your own container, with the venue address from `legacy.location`.
6. **Disclaimer on every page** — the operator's legal text, repeated because each page is handed out separately.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.