# Welcome

Welcome to Ventrata's OCTO API Developer Documentation!

This documentation describes Ventrata's implementation of the [OCTO API Specification](https://docs.octo.travel/) for resellers (OTAs, marketplaces, and other distributors) that need API connectivity with suppliers using Ventrata as their ticketing platform.

![OCTO Founding Member](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FMYOxyG8Nzu1gSNp85je4%2Focto-badge-founding-member.svg?alt=media\&token=5571066b-3299-48cb-ac90-aace0d1752ff) ![OCTO Supported](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Flx8982UomnWwUH72yaKj%2Focto-badge-supported.svg?alt=media\&token=8b7cc705-e883-439c-a17b-074172028df1)

## About Ventrata

Ventrata is an enterprise ticketing platform designed for high-volume attraction, tour, and activity operators. The platform supports online, in-person, and third-party sales, with functionality for resource management, hardware integrations, and 24/7 live support.

Ventrata's solutions are used by leading operators, including Big Bus Tours, Sightseeing Pass, Tootbus, Historic Tours of America, Boston Duck Tours, Magnicity / M56 Group, Pilsner Urquell Experience, Fat Tire Tours, Museum of Illusions, Gray Line, and City Sightseeing operators:

{% content-ref url="/pages/QCgnfmcQ1vc9zlYM9SlX" %}
[Ventrata Clients](/additional-resources/ventrata-clients)
{% endcontent-ref %}

Resellers (online travel agencies, travel marketplaces, city card operators, etc.) integrate directly with Ventrata's OCTO API to access supplier availability, pricing, scan-ready vouchers, and more. Major resellers, including Viator, GetYourGuide, Expedia, Groupon, Klook, Headout, Go City, TUI Musement, and Tiqets, have integrated with Ventrata.

**There is no fee for resellers working with Ventrata clients to use the OCTO API and related support.**

Learn more about Ventrata at <https://ventrata.com/>

## About OCTO

OCTO (Open Connectivity for Tourism) is an open standard API specification for the in-destination experiences sector of the travel industry. The standard defines agreed-upon schemas, endpoints, and capabilities commonly needed when connecting platforms, resellers, OTAs, and other technologies in tours, activities, and attractions.

OCTO is developed and administered by a member-based not-for-profit organization OCTO Standards NP Inc.

Ventrata is a founding member of OCTO and one of the earliest adopters of the standard. The OCTO API is also adopted by Peek Pro, Xola, Zaui, Anchor, and others.

{% content-ref url="/pages/7pZaVA4eq2BXbMsFXfoj" %}
[Other OCTO Implementations](/additional-resources/other-octo-implementations)
{% endcontent-ref %}

Learn more about OCTO at <https://www.octo.travel/>. Support the initiative by becoming a member!

Visit <https://docs.octo.travel/> and <https://github.com/octotravel> for official OCTO specifications.


# Steps to Integrate

A practical process for integrating with Ventrata's OCTO API for resellers

{% hint style="info" %}
This page provides a step-by-step overview for resellers connecting to suppliers that use Ventrata. For other use cases (for example, a Ventrata client building their own checkout or an operator connection), contact <connectivity@ventrata.com>.
{% endhint %}

{% stepper %}
{% step %}

### Step 1: Review Documentation and Plan

Review this documentation and familiarize your team with the OCTO API and Ventrata's implementation.

Decide which [Endpoints and Capabilities](/getting-started/request-capabilities) you will implement. Ventrata requires all resellers to support OCTO core endpoints as a minimum:

* [Products](/octo-core/products)
* [Availability](/octo-core/availability)
* [Booking](/octo-core/bookings)

Implementing capabilities is optional, but Ventrata strongly recommends at least [Pricing](/capabilities/pricing), because dynamic pricing is now widely used by [Ventrata clients](/additional-resources/ventrata-clients).

Contact us if you have implementation questions or want to discuss specific capabilities.
{% endstep %}

{% step %}

### Step 2: Develop

Build the integration. Most resellers complete development in 2 to 10 days. If you already support OCTO with another booking or ticketing system, you can usually proceed directly to [testing](/getting-started/test-credentials).

Test as you build using Ventrata's EdinExplore account, a fictional supplier created for this purpose. It includes common product configurations and gives access to products, bookings, and API logs. See [Test Credentials](/getting-started/test-credentials) for access.
{% endstep %}

{% step %}

### Step 3: Test

After self-testing your implementation with EdinExplore, contact <connectivity@ventrata.com> for integration review and approval. We will also require your company name, a logo, a favicon, a short, supplier facing description and a link to your website for your listing on Ventrata.

The review response target is 1 to 2 business days. We may ask for additional test bookings (including updates and cancellations), a voucher sample, and confirmation of supported capabilities before go-live approval.
{% endstep %}

{% step %}

### Step 4: Go Live

After approval, your integration is added to Ventrata's partner list and documented in our [helpdesk](https://ventrata.crisp.help/en/category/connectivity-1dqf093/), so suppliers can enable it and share API keys with your team.

At that point, you can contact [Ventrata clients](/additional-resources/ventrata-clients) to connect products and begin selling.
{% endstep %}
{% endstepper %}


# Glossary of Terms

OCTO defines core terms that are re-used throughout the specification. Below we include some of the key terms you need to know before getting started:

| Term          | Description                                                                      |
| ------------- | -------------------------------------------------------------------------------- |
| **Reseller**  | The distributor connecting to a supplier via the API to resell products.         |
| **Supplier**  | The operator that provides products and uses Ventrata.                           |
| **Product**   | An attraction, activity, or tour offered by a supplier.                          |
| **Option**    | A product variant. Every product has at least one option.                        |
| **Unit**      | A ticket type, for example Adult, Child, or Senior.                              |
| **Unit Item** | A line item for a specific unit inside a booking.                                |
| **Booking**   | A reservation for a specific product option with one or more unit items.         |
| **Voucher**   | A single admission document (barcode, QR code, PDF, etc.) for the whole booking. |
| **Ticket**    | An admission document (barcode, QR code, PDF, etc.) for each unit item.          |


# Authentication

OCTO uses Bearer authentication. To authenticate requests, send an API key as a Bearer token in the `Authorization` header:

```http
Authorization: Bearer {your_API_key}
```

The supplier issues your API key by creating a connection for your reseller account in Ventrata. The same connection also controls product access and applicable pricing.

The API key is a UUID value, for example: `5bd1629a-323e-4edb-ac9b-327ef51e6136`

{% hint style="warning" %}
Note that in Ventrata's implementation of OCTO, **the API key provides access to a single supplier**. You will have different API keys for each supplier you'd like to connect with.
{% endhint %}

To obtain an API key for Ventrata's test supplier account during development, see [Testing Credentials](/getting-started/test-credentials).

All API requests must be made over [HTTPS](https://en.wikipedia.org/wiki/HTTPS). Calls made over plain HTTP will fail.

Requests without authentication fail. If the token is invalid or deactivated by the supplier, the API returns `403 Forbidden`.

{% hint style="warning" %}
API keys must be kept secure. You are responsible for any bookings made with your API key. If your key is disclosed publicly, ask the supplier to delete and recreate your connection, or contact <connectivity@ventrata.com> to rotate the key.
{% endhint %}

Every `POST`, `PATCH`, and `DELETE` request must use the `Content-Type: application/json` header, and the request body must be a JSON-encoded string. Every endpoint will return JSON unless otherwise stated.


# Test Credentials

You can test your integration using Ventrata's **EdinExplore**, a fictional supplier account created for testing and demonstration.

This account includes common product configurations and gives you access to products, bookings, and Ventrata API logs.

## Obtaining Test Credentials

Register for test credentials here:

<https://dashboard.ventrata.com/octo/signup>

The signup form asks for your company name, email, and password. You will use these credentials to access the [Booking Portal](#booking-portal), where you can review bookings, check availability, and view logs.

After creating your account, you will see a screen similar to this:

![Account setup screen with endpoint and key](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fytea0hW1hw7sPpIwrJG4%2FCleanShot%202023-06-02%20at%2021.36.31%402x.png?alt=media\&token=c4fb27de-907d-491b-a5f6-6abe64120cd7)

The API endpoint and key shown on that page can be used to test your integration with EdinExplore.

### Booking Portal

Use your new credentials to sign in to the EdinExplore agent portal:

<https://edinexplore.portal.ventrata.site/>

It will look like this:

!\[EdinExplore agent portal]\(../.gitbook/assets/CleanShot 2023-06-02 at <21.46.47@2x.png>)

On the `Bookings` tab, you can view all bookings made through the reseller portal and API. This helps verify field values and confirm that requests are being recorded correctly.

![Sample of a booking in the agent portal](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M7bgGIyO7QYNOfUMfxh%2F-M9NtE3CL1-nNIQWvXW-%2F-M9NwE_-2Jq7PZnb1dTG%2FScreenshot%202020-06-09%20at%2013.55.57.png?alt=media\&token=bc9478d3-949c-4588-b922-442778a6ccf6)

### API Logs

In addition to the booking portal, the `API Logs` tab lists all API requests received for your credentials.

![](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M7bgGIyO7QYNOfUMfxh%2F-MFeIWGlsNZDOrAfe09f%2F-MFeJMGP3e7Kz61EzMo2%2Fimage.png?alt=media\&token=99d1c9e9-7418-435e-912c-bf7ea327bb70)

Selecting a request opens a request/response view.

![](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M7bgGIyO7QYNOfUMfxh%2F-MFeIWGlsNZDOrAfe09f%2F-MFeJt1Gka1t-yVpqQMt%2Fimage.png?alt=media\&token=0bf83b31-ac01-4e7b-9aee-1620b0dbb6ce)

## Live Testing

If you need to test with live supplier credentials, use the `Octo-Env: test` request [header](/getting-started/headers).

This header marks bookings made with live credentials as test sales in Ventrata. Test sales do not consume availability, barcodes do not redeem, and they are not invoiced. Use `Octo-Env: test` for test bookings and `Octo-Env: live` to disable test mode and sell live.

Suppliers can force your connection into test mode, which processes all requests as `Octo-Env: test`. This is commonly used when suppliers want to review test bookings before approving go-live.


# Headers

You must supply a set of HTTP headers when making a request. These headers can include both standard HTTP headers and custom OCTO API or Ventrata headers.

Below are the required standard request headers, custom headers we recommend using, and useful headers you can expect in Ventrata responses.

## Request Headers

| Header              | Required    | Description                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Authorization`     | Required    | Your [Authentication](/getting-started/getting-started) `Bearer` token.                                                                                                                                                                                                                                                                                                                 |
| `Content-Type`      | Required    | Must be `application/json` for all `POST`, `PATCH`, and `DELETE` requests.                                                                                                                                                                                                                                                                                                              |
| `Octo-Capabilities` | Required    | A list of [Capabilities](/getting-started/request-capabilities) to include in the response, for example `Octo-Capabilities: octo/pricing, octo/content`. Include the header but leave it empty if no capabilities are needed. If this header is not included, Ventrata returns a `400` error.                                                                                           |
| `Octo-Env`          | Recommended | This can mark any booking performed with live credentials as a test sale in Ventrata. This means it will not consume availability, barcodes will not work, and you will not be invoiced. Use `Octo-Env: test` for test bookings and `Octo-Env: live` to turn it off and sell live. See [Live Testing](/getting-started/test-credentials#live-testing).                                  |
| `Accept-Language`   | Optional    | This conforms to the regular HTTP specification for language. If the supplier has translated their content, it returns content in the specified language when possible, and error messages are also translated. For example, send `Accept-Language: fr` and the server responds with `Language: fr` when that language is available. See [Localization](/getting-started/localization). |

## Response Headers

| Header                     | Description                                                                                                                                                                                                                                      |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `Content-Type`             | `application/json`                                                                                                                                                                                                                               |
| `Octo-Capabilities`        | A list of [Capabilities](/getting-started/request-capabilities) initialized with your request, for example `Octo-Capabilities: octo/pricing, octo/content`.                                                                                      |
| `Octo-Env`                 | Returns `test` if the request is in test, or `live` if it is not, depending on your request `Octo-Env` value and whether the supplier forced your connection to `test` mode. See [Live Testing](/getting-started/test-credentials#live-testing). |
| `Content-Language`         | The language of returned content. See [Localization](/getting-started/localization) for how to set it.                                                                                                                                           |
| `Octo-Available-Languages` | A list of languages the supplier has translated content into. See [Localization](/getting-started/localization).                                                                                                                                 |


# Errors

OCTO responds to every request with either `200 OK` when everything is valid or `400 Bad Request` when it is not. In the case of `400 Bad Request`, the response body looks like this:

```json
{
  "error": "INVALID_PRODUCT_ID",
  "errorMessage": "The Product ID was invalid or missing",
  "productId": "123"
}
```

You will always receive `error` and `errorMessage`:

| Field          | Description                                                                                                           |
| -------------- | --------------------------------------------------------------------------------------------------------------------- |
| `error`        | The error code. A table of possible error codes is shown below.                                                       |
| `errorMessage` | A human-readable error message that is translated depending on the language provided by the `Accept-Language` header. |

Depending on the error code, we may also pass additional fields that make it easier to understand what is wrong with your request. In the example above, we provide `productId` and pass the value that was sent in the request, indicating that the `productId` of `123` is not valid.

## List of Error Codes

Below is a list of the error codes and a description of what each means. Further down this page, we also provide example response bodies for the error codes that include additional attributes.

| Code                      | Description                                                                                                                                                         |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `INVALID_PRODUCT_ID`      | Missing or invalid `productId` in the request.                                                                                                                      |
| `INVALID_OPTION_ID`       | Missing or invalid `optionId` in the request.                                                                                                                       |
| `INVALID_UNIT_ID`         | Missing or invalid `unitId` in the request.                                                                                                                         |
| `INVALID_AVAILABILITY_ID` | Missing or invalid `availabilityId` in the request.                                                                                                                 |
| `INVALID_BOOKING_UUID`    | Missing or invalid booking UUID, or if you are confirming the booking, the booking may already have expired.                                                        |
| `BAD_REQUEST`             | The request body is not formatted correctly, has missing required fields, or contains incorrect data types.                                                         |
| `UNPROCESSABLE_ENTITY`    | The request body is technically correct but cannot be processed for other reasons, for example if a booking is cancelled after the cancellation cutoff has elapsed. |
| `INTERNAL_SERVER_ERROR`   | The backend server is down or there is a network outage.                                                                                                            |
| `UNAUTHORIZED`            | The API key was not sent in the `Authorization` header to an endpoint that requires authentication.                                                                 |
| `FORBIDDEN`               | The API key was invalid or revoked by the backend system, or you are trying to access an endpoint/resource you do not have access to.                               |

As explained above, it is also possible for specific error codes to have additional attributes that help you diagnose what is wrong with your request. Below are all specific errors that contain these attributes:

### `INVALID_PRODUCT_ID`

```json
{
  "error": "INVALID_PRODUCT_ID",
  "errorMessage": "The Product ID was invalid or missing",
  "productId": "123"
}
```

### `INVALID_OPTION_ID`

```json
{
  "error": "INVALID_OPTION_ID",
  "errorMessage": "The Option ID was invalid or missing",
  "optionId": "321"
}
```

### `INVALID_UNIT_ID`

```json
{
  "error": "INVALID_UNIT_ID",
  "errorMessage": "The Unit ID was invalid or missing",
  "unitId": "senior"
}
```

### `INVALID_AVAILABILIY_ID`

```json
{
  "error": "INVALID_AVAILABILIY_ID",
  "errorMessage": "The Availability ID was invalid or missing",
  "availabilityId": "2020-01-01T10:30+08:00"
}
```


# Localization

Content available for multiple languages

Suppliers can store content in multiple languages in Ventrata. Requests should include the `Accept-Language` [header](/getting-started/headers), ideally matching the language preferences sent by the client browser or user agent.

More information about the structure of that header is available on [MDN](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept-Language).

The API attempts to match the preferred languages against languages already translated by the supplier. The response includes a `Content-Language` header indicating the language returned, consistent with the HTTP standard.

Use the product operation below with the `Accept-Language` header to request localized content:

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/products/{productId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

The response `Content-Language` reflects the resolved language (for example English when no other translation exists):

If you cache content locally, use the `Octo-Available-Languages` header, which lists languages translated by the supplier.

You can repeat the request with each available language to retrieve localized content.


# Endpoints & Capabilities

Ventrata supports all OCTO Core endpoints plus optional capability extensions.

This page documents the reseller-facing `octo/*` capability set from the API source (`dashboard/app/controllers/apis/octo_controller.rb` and `dashboard/app/controllers/apis/octo/*_capability.rb`).

## OCTO Core Endpoints

Core endpoint routes are documented in these pages:

* [Products](/octo-core/products)
* [Availability](/octo-core/availability)
* [Bookings](/octo-core/bookings)

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/capabilities" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/whoami" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

## `octo/*` Capability Coverage

| Capability ID        | Internal | Documentation                                    | API Surface                                                                                      |
| -------------------- | -------- | ------------------------------------------------ | ------------------------------------------------------------------------------------------------ |
| `octo/pricing`       | No       | [Pricing](/capabilities/pricing)                 | Pricing fields across products/availability/bookings/orders/gifts.                               |
| `octo/content`       | No       | [Content](/capabilities/content)                 | Extends product/option/unit/availability/booking content fields.                                 |
| `octo/offers`        | No       | [Promotions / Offers](/capabilities/offers)      | Supplier offers and offer-aware pricing/booking responses.                                       |
| `octo/extras`        | No       | [Extras](/capabilities/extras)                   | Extra upsell inventory and booking extra-items behavior.                                         |
| `octo/packages`      | No       | [Packages](/capabilities/packages)               | Package includes and package booking flows.                                                      |
| `octo/pickups`       | No       | [Pickups](/capabilities/pickups)                 | Pickup/dropoff fields on product/availability/booking.                                           |
| `octo/questions`     | No       | [Custom Questions](/capabilities/questions)      | Question schemas and `questionAnswers` write flows.                                              |
| `octo/waivers`       | No       | [Waivers](/capabilities/waivers)                 | Waiver templates on products and waiver submission/status fields on booking and unit-item flows. |
| `octo/resources`     | No       | [Resources](/capabilities/resources)             | Availability resources and resource allocations.                                                 |
| `octo/rentals`       | No       | [Rentals](/capabilities/rentals)                 | `rentalDurationId` behavior across product/availability/booking.                                 |
| `octo/redemption`    | No       | [Redemption](/capabilities/redemption)           | Redemption lookup, redeem/unredeem, no-show, and credential resolution flows.                    |
| `octo/mappings`      | No       | [Self-Service Mapping](/capabilities/mappings)   | Self-service mapping write/read flows.                                                           |
| `octo/cart`          | No       | [Multi-Booking Cart](/capabilities/cart)         | Order create/list/update/confirm/cancel flows.                                                   |
| `octo/gifts`         | No       | [Gift Vouchers](/capabilities/gift-vouchers)     | Gift voucher create/list/update/confirm/cancel flows.                                            |
| `octo/checkin`       | No       | [Online Check-in](/capabilities/online-check-in) | Check-in lookup and check-in fields on bookings/orders/gifts.                                    |
| `octo/cardPayments`  | No       | [Card Payments](/capabilities/card-payments)     | Card payment flows on booking/order/gift plus card payment lookup.                               |
| `octo/memberships`   | No       | [Memberships](/capabilities/memberships)         | Membership lookup and membership-booking listing.                                                |
| `octo/adjustments`   | No       | [Price Adjustments](/capabilities/adjustments)   | Extends booking create/update pricing inputs (`adjustments`).                                    |
| `octo/webhooks`      | No       | [Webhooks](/capabilities/webhooks)               | Webhook create/update/list/delete and trigger flows.                                             |
| `octo/waitlists`     | No       | [Waitlists](/capabilities/waitlists)             | Waitlist create flow.                                                                            |
| `octo/identities`    | Yes      | [Identities](/capabilities/identities)           | Identity create/update/delete and `identityId` linkage.                                          |
| `octo/campaigns`     | No       | [Campaigns](/capabilities/campaigns)             | Campaign listing endpoint support.                                                               |
| `octo/notifications` | No       | [Notifications](/capabilities/notifications)     | Notification subscription CRUD flows.                                                            |

## Capability Object Shape

Capabilities returned on product payloads and `/octo/capabilities` use this shape:

| Field          | Description                                          |
| -------------- | ---------------------------------------------------- |
| `id`           | Capability ID to include in `Octo-Capabilities`.     |
| `revision`     | Supported, backward-compatible capability revision.  |
| `required`     | Whether capability is required to sell that product. |
| `dependencies` | Capability IDs that are auto-included when needed.   |
| `docs`         | Documentation URL when provided by the API.          |

## Supplying Capabilities

Send requested capability IDs in the `Octo-Capabilities` request header on any OCTO endpoint (or `X-Capabilities` as the legacy alias). Capability IDs are requested uniformly via headers across all endpoints.

The response echoes applied capabilities in the `Octo-Capabilities` response header.


# Products

List available products for purchase

Either you have a database of products that you need to map to products returned in this API, or you choose to import the product list from this endpoint to your system.

{% hint style="info" %}
Ventrata has also implemented a self-service mapping capability that substantially reduces the burden of maintaining mappings. We recommend you implement this if you are able to. [Click here](/capabilities/mappings) for the documentation.
{% endhint %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/products" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Depending on the capabilities you enable, additional fields may be merged into this core product schema by capability modules. The capabilities that were applied to the request are returned in the `Octo-Capabilities` response header.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/products/{productId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

This endpoint does not add capability-specific query parameters.


# Availability

Getting availability for a product

The first step when making a sale is to check availability. If `allowFreesale` is set to `true` on the product then this step is optional, but it is still recommended to detect closures and operational limits.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability/calendar" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability/calendar/batch" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability/batch" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}


# Bookings

Reserving availability and making a booking

The steps to making a booking are as follows:

1. **Check Availability:** Check availability and retrieve an availability ID.
2. **Booking Reservation:** Create a booking that reserves availability while you collect payment and customer details.
3. **Booking Confirmation:** Confirm the booking once payment is complete.

All routes in this page are public OCTO routes under `https://api.ventrata.com/octo`.

All booking routes are documented in the [Endpoints](#endpoints) section below.

## Endpoints

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings/{uuid}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings/{uuid}/confirm" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings/{uuid}/cancel" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings/{uuid}/extend" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings/{uuid}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/bookings" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

## After Confirmation: Fields to Use

When `POST /bookings/{uuid}/confirm` succeeds, prioritize these fields from the booking response:

* `booking.supplierReference`: Human-readable supplier reference. Give this to the guest and store it for customer support and billing reconciliation.
* `booking.voucher`: Use when `booking.deliveryMethods` contains `VOUCHER` (one ticket media object per booking).
* `booking.unitItems[].ticket`: Use when `booking.deliveryMethods` contains `TICKET` (one ticket media object per person/unit item).
* `booking.pricing.retail`: Retail amount in minor units that you must charge the guest for the booking.
* `booking.pricing.net`: Net amount in minor units that the supplier will invoice for the booking.

If `booking.deliveryMethods` contains both `VOUCHER` and `TICKET`, the reseller can choose what the guest prefers: one voucher for the booking, or one ticket per person.

The `booking.voucher` and `booking.unitItems[].ticket` objects have the same shape and provide guest-facing media in `deliveryOptions` (for example `PDF_URL`, `QRCODE`, and wallet links).

```json
{
  "supplierReference": "SUP-20260304-009871",
  "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
  "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
  "availabilityId": "2026-03-04T18:30:00+01:00",
  "deliveryMethods": ["VOUCHER", "TICKET"],
  "voucher": {
    "deliveryOptions": [
      {
        "deliveryFormat": "PDF_URL",
        "deliveryValue": "https://api.ventrata.com/octo/download/booking/89fe0192-ddcd-430a-b285-e1396a4725d2.pdf"
      }
    ]
  },
  "unitItems": [
    {
      "ticket": {
        "deliveryOptions": [
          {
            "deliveryFormat": "QRCODE",
            "deliveryValue": "TKT-11111111"
          }
        ]
      }
    }
  ],
  "pricing": {
    "retail": 4600,
    "net": 3220,
    "currency": "USD",
    "currencyPrecision": 2
  }
}
```

For `GET /bookings`, include one primary filter from this set:

* `resellerReference`
* `supplierReference`
* `localDate`
* `localDateStart` + `localDateEnd`
* `availabilityId`
* `utcCreatedAtStart` + `utcCreatedAtEnd`
* `utcUpdatedAtStart` + `utcUpdatedAtEnd`
* `utcRedeemedAtStart` + `utcRedeemedAtEnd`
* `utcNoshowedAtStart` + `utcNoshowedAtEnd`
* `utcRebookedAtStart` + `utcRebookedAtEnd`
* `utcCancelledAtStart` + `utcCancelledAtEnd`
* `contactEmailAddress`
* `contactPhoneNumber`
* `contactLastName`

Supported status filter values are:

* `REDEEMED`
* `NO_SHOW`
* `ON_HOLD`
* `CANCELLED`
* `EXPIRED`
* `PENDING`
* `REJECTED`
* `REBOOKED`
* `QUOTE`
* `CONFIRMED`

Pagination notes:

* `page` and `perPage` are supported.
* `Octo-Total-Pages` response header is set when paginating.
* When `page` is omitted, the API may aggregate all pages internally and return one combined array.

Voucher/ticket delivery URLs are returned directly in `voucher.deliveryOptions[].deliveryValue` and `unitItems[].ticket.deliveryOptions[].deliveryValue`.


# Pricing

Provides pricing information to various endpoints

To use this capability, add `octo/pricing` to your `Octo-Capabilities` header.

This capability supports dynamic pricing where the price of the product can be changed day by day and even at different start times. Make sure your system is able to support this level of pricing before you integrate with it.

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

This pricing extension is returned on both `GET /products` and `GET /products/:productId`.

On the response, pricing adds the following fields on the Product object:

`defaultCurrency` is the fallback currency. `availableCurrencies` are all valid currencies for this product. `includeTax` indicates whether product prices already include tax. `hidePricingFrom` indicates whether from-prices should be hidden in UI contexts.

`pricingPer` indicates whether pricing is per unit (most common) or per booking.

If `pricingPer = "UNIT"`, each option unit/item includes `pricingFrom`.

If `pricingPer = "BOOKING"`, each option includes `pricingFrom` instead.

If `currency` is omitted, pricing arrays include one object per value in `availableCurrencies`. If `currency` is set (or set to `default`), pricing arrays contain a single object.

{% hint style="warning" %}
Throughout this capability, fields ending with `From` are indicative prices and not final prices. Make sure this is communicated clearly to customers.
{% endhint %}

This capability extends availability calendar routes documented in [Availability](/octo-core/availability#availability-calendar):

* `POST /availability/calendar`
* `GET /availability/calendar`

This pricing extension is available on both `GET /availability/calendar` and `POST /availability/calendar`.

The documentation above only shows the additions this capability adds to the availability calendar endpoint. See the documentation [here](/octo-core/availability#availability-calendar) to see the full request parameters and response object.

`units` supports nested fields:

Using the availability calendar endpoint for pricing is designed to make it easy to generate a pricing calendar for example on Google Travel:

![Pricing calendar example](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-M7bgGIyO7QYNOfUMfxh%2F-M9FJR76XCztVEaXvWcm%2F-M9FNv2YSMk-oIninjcb%2F68747470733a2f2f692e696d6775722e636f6d2f793039325676392e706e67.png?alt=media\&token=6be1bad1-7ba4-45eb-98c3-ef9a12a42dcd)

Each availability object is given:

* `unitPricingFrom`: an array of unit/item prices, each with `unitId` and `unitType`
* `pricingFrom`: a total pricing object for the availability (for `pricingPer = UNIT`, this is only meaningful once `units` are passed)

If you pass `units`, `pricingFrom` returns the total pricing for that selection. For `pricingPer = BOOKING`, `pricingFrom` is still returned without unit selection because booking pricing is not ticket-count driven.

Having the `pricingFrom` value calculated for you makes it much easier to display a single price on each date on the calendar (assuming the guest has chosen how many units they want before you display the calendar).

For `pricingPer = BOOKING`, `unitPricingFrom` may still be present for item-style units (type `OTHER`) and can be an empty array.

This capability extends availability check routes documented in [Availability](/octo-core/availability#availability-check):

* `POST /availability`
* `GET /availability`

This pricing extension is available on both `GET /availability` and `POST /availability`.

`unitPricing` rows include `unitId` and `unitType`, plus the shared pricing object fields described earlier.

`units` uses the same schema shown in the availability calendar section (`id`, `quantity`, optional `weightValue` and `weightUnit`). Availability `extras` use objects with `id` and `quantity`.

This endpoint is the availability check endpoint which has been extended to add pricing. We only document the added parameters here, to see the full documentation for the original availability check you can find it [here](/octo-core/availability#availability-check).

Notice how the response fields are `unitPricing` and `pricing` (without the From suffix). That is because this is the final price, and this is what the booking will be once confirmed.

Batch variants (`POST /availability/batch` and `POST /availability/calendar/batch`) return the same pricing extensions because they proxy these same endpoints.

This capability extends booking write routes documented in [Bookings](/octo-core/bookings#endpoints):

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

This capability extends booking responses to add a final `pricing` object. The final price includes tax and is the amount to show/pay.

This pricing payload is returned anywhere a booking object is serialized (booking write/read/cancel/extend routes in [Bookings](/octo-core/bookings#endpoints)).

If request `pricing` is provided, it must match the server-calculated booking totals.

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

If a partner has enforced price-matching and no matching `pricing` object is sent, the request fails with `PRICING_MATCH_REQUIRED`.

Write endpoints that build/update booking/order/gift records also accept `currency`. You can pass `default` to use the preferred currency automatically.

Booking payloads can include pricing at these paths:

* `pricing`
* `availability.pricing`
* `availability.unitPricing[]`
* `option.pricing` (for `pricingPer = BOOKING`)
* `option.units[].pricing` and `option.units[].pricingFrom` (depending on unit type/selection state)
* `unitItems[].pricing`
* `unitItems[].unit.pricing`

Additional pricing serialization using the same pricing object schema:

* Order responses include `pricing` on order write/read/cancel/extend routes (see [Multi-Booking Cart](/capabilities/cart)).
* Gift responses include `pricing` on gift write/read/cancel/extend routes (see [Gift Vouchers](/capabilities/gift-vouchers)).
* Destination objects serialized by `octo/content` include `defaultCurrency` and `availableCurrencies`.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "unitPricing": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "unitPricingFrom": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "extraPricing": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ],
  "extraPricingFrom": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ]
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "unitPricing": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "unitPricingFrom": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "extraPricing": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ],
  "extraPricingFrom": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ]
}
```

### `AvailabilityCalendar`

```json
{
  "// ...rest of availability calendar object": "...",
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "unitPricingFrom": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "extraPricingFrom": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ]
}
```

### `AvailabilityCalendarBatchRow`

```json
{
  "// ...rest of availability calendar batch row object": "...",
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "unitPricingFrom": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "extraPricingFrom": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ]
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `Error`

```json
{
  "// ...rest of error object": "...",
  "availableCurrencies": [
    "USD",
    "EUR"
  ],
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `ExtraPricing`

```json
{
  "// ...rest of extra pricing object": "...",
  "includedTaxes": [
    {
      "name": "Sales Tax",
      "original": 2000,
      "retail": 1800,
      "shortDescription": "Local sales tax",
      "net": 1600
    }
  ]
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `Money`

```json
{
  "// ...rest of money object": "...",
  "includedTaxes": [
    {
      "name": "Sales Tax",
      "original": 2000,
      "retail": 1800,
      "shortDescription": "Local sales tax",
      "net": 1600
    }
  ]
}
```

### `Option`

```json
{
  "// ...rest of option object": "...",
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "unitPricing": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "unitPricingFrom": [
    {
      "unitId": "unit_adult",
      "unitType": "ADULT",
      "original": 12000,
      "retail": 10000,
      "net": 9000,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 1200,
          "retail": 1000,
          "net": 900
        }
      ]
    }
  ],
  "extraPricing": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ],
  "extraPricingFrom": [
    {
      "extraId": "extra_fast_track",
      "original": 2000,
      "retail": 1800,
      "net": 1600,
      "currency": "USD",
      "currencyPrecision": 2,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "original": 200,
          "retail": 180,
          "net": 160
        }
      ]
    }
  ]
}
```

### `Pricing`

```json
{
  "// ...rest of pricing object": "...",
  "includedTaxes": [
    {
      "name": "Sales Tax",
      "original": 2000,
      "retail": 1800,
      "shortDescription": "Local sales tax",
      "net": 1600
    }
  ]
}
```

### `Product`

```json
{
  "// ...rest of product object": "...",
  "availableCurrencies": [
    "USD",
    "EUR"
  ],
  "defaultCurrency": "USD",
  "includeTax": true,
  "includedTaxes": [
    {
      "name": "Sales Tax",
      "shortDescription": "Local sales tax",
      "original": 2000,
      "retail": 1800,
      "net": 1600
    }
  ],
  "hidePricingFrom": true,
  "pricingPer": "UNIT",
  "pricingMultiplier": 10.0
}
```

### `Unit`

```json
{
  "// ...rest of unit object": "...",
  "pricingFrom": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  },
  "pricing": {
    "original": 22000,
    "retail": 20000,
    "net": 18000,
    "currency": "USD",
    "currencyPrecision": 2,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "original": 2000,
        "retail": 1800,
        "net": 1600
      }
    ]
  }
}
```

### `UnitPricing`

```json
{
  "// ...rest of unit pricing object": "...",
  "includedTaxes": [
    {
      "name": "Sales Tax",
      "original": 2000,
      "retail": 1800,
      "shortDescription": "Local sales tax",
      "net": 1600
    }
  ]
}
```


# Content

Adds extra content fields to products, options and units.

To use this capability, add `octo/content` to your `Octo-Capabilities` header.

This capability extends the Supplier, Destination, Category, Product, Option, Unit, Item, Availability and Booking schemas with additional content fields. When used with `octo/cart` it also extends Order responses.

{% hint style="warning" %}
The content provided by this endpoint belongs to the supplier, so please make sure you have their express permission before using it online.
{% endhint %}

* `itinerary.type`: Enum with one of the following values:
  * `START`: The starting or meeting location.
  * `POI`: A point of interest visited en route.
  * `EVENT`: An event that happens, for example `Lunch` or `Shopping Break`.
  * `END`: The ending or final location.
* `itinerary.travelTime`: The travel time required to get to this location.
* `itinerary.duration`: How much time is spent on this itinerary item.

The following helper objects are also used by this capability:

* `notice`: `id`, `title`, `shortDescription`, `coverImageUrl`
* `tourGroup`: `id`, `internalName`, `title`, `shortDescription`, `icon`
* `fare`: `id`, `internalName`, `title`, `shortDescription`, `fareGroup`
* `fareGroup`: `id`, `internalName`, `title`, `shortDescription`
* `point`: `id`, `internalName`, `title`, `shortDescription`, `pointGroup`
* `pointGroup`: `id`, `internalName`, `title`, `shortDescription`
* `font`: `id`, `name`, `normalTtfUrl`, `boldTtfUrl`, `italicTtfUrl`, `boldItalicTtfUrl`

When `octo/extras` is also enabled, each `extra` object includes:

* `title`
* `shortDescription`
* `coverImageUrl`
* `duration`
* `durationAmount`
* `durationUnit`

## Products

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

This capability extends the `GET /products` endpoint with additional content filtering parameters.

## Booking and Order Parameters

`termsAccepted` is supported by content capability as an input field and response field.

### Booking Endpoints

`termsAccepted` can be sent in the request body for these routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

Base booking schema: [Bookings](/octo-core/bookings#endpoints). This page documents only the `termsAccepted` addition.

### Order Endpoints (with `octo/cart`)

`termsAccepted` can be sent in the request body for these routes:

* `POST /orders`
* `PATCH /orders/{orderId}`
* `PATCH /orders/{orderId}/preview`
* `POST /orders/{orderId}/confirm`

It is accepted:

* At the order root (`termsAccepted`) and applies to all standalone bookings in the order.
* Inside nested booking payloads (`bookings[].termsAccepted`) when creating/updating bookings through order requests.

If both are supplied, the order-level `termsAccepted` value takes precedence.

Base order schema: [Multi-Booking Cart](/capabilities/cart).

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "termsAccepted": true
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "termsAccepted": true
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "termsAccepted": true
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "termsAccepted": true
}
```

### `Option`

```json
{
  "// ...rest of option object": "...",
  "itinerary": [
    {
      "name": "Morning City Tour",
      "type": "STANDARD",
      "description": "Morning departure with central pickup included.",
      "address": "123 Main St, San Francisco, CA"
    }
  ]
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "termsAccepted": true
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "termsAccepted": true
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "termsAccepted": true
}
```


# Promotions / Offers

Adds the ability to apply offer codes, automatic public offers, comparisons, and combination discounts

To use this capability, add `octo/offers` to your `Octo-Capabilities` header.

This capability depends on `octo/pricing`.

Related capabilities:

* `octo/cart` is required for `offerCombinations` on order responses.
* `octo/gifts` is required for gift offer endpoints/fields.
* `octo/extras` is required for offer fields on `extraItems`.

All routes below are under the `/octo` prefix.

The offers capability lets you apply promotion codes to bookings/gifts, automatically apply eligible public offers, return upsell comparisons, and return discounted product combinations.

## Combination Product Discovery

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

When `offerCode` is a combination code (`combination_<...>`), product scope is expanded to include the combination target product, so you can fetch product/options/availability for that target using the same code.

## Offer Object

The same offer object is used in:

* `offers[]` and `offer` on availability responses
* `offer` and `offers[]` on booking/gift/extra-item responses
* `offer` in `offerCombinations[]`

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/offers" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

## Pricing Field Added By Offers

Offers adds `offerDiscount` to pricing fragments emitted through pricing serializers, including:

* availability `pricing` / `pricingFrom`
* availability `unitPricing[]` / `unitPricingFrom[]`
* booking/gift/order `pricing`
* unit item / purchase item / extra item `pricing`

## Get Available Offers

This capability extends availability routes documented in [Availability](/octo-core/availability):

* `POST /availability`
* `POST /availability/calendar`
* `POST /availability/batch`
* `POST /availability/calendar/batch`

### Response Additions Per Availability Object

If no `offerCode` is sent, new booking/gift flows auto-select the first eligible public offer.

## Discount Booking

Offer code can be sent on these booking write routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

It can also be sent inside order payloads on:

* `bookings[].offerCode` in `POST /orders`, `PATCH /orders/:orderId`, `PATCH /orders/:orderId/preview`, `POST /orders/:orderId/confirm`

### Booking Response Additions

These fields are present on any serialized booking response, including:

* `GET /bookings/{uuid}`
* `GET /bookings`
* booking write responses
* bookings embedded in serialized order responses

## Product Comparisons

Comparisons are exposed on serialized booking objects from base booking routes (see [Bookings](/octo-core/bookings#endpoints)).

`offerComparisons[]` is returned on booking objects (including booking responses embedded in order responses).

Comparisons are returned only for persisted, active, standalone, non-combination bookings; otherwise the field is `[]`.

## Product Combinations

Combinations are exposed on serialized order objects from base cart routes (see [Multi-Booking Cart](/capabilities/cart)).

Combinations are returned on order objects as `offerCombinations[]` (requires `octo/cart`). They are also present on other order responses that serialize an order (`POST/PATCH /orders`, `GET /orders`, etc.).

To apply a combination, create/update a booking with the returned `offerCode` and matching `productId`/`optionId`.

## Gift Offers

Requires `octo/gifts`.

Offer code can be sent on:

* `POST /gifts`
* `PATCH /gifts/{uuid}`
* `PATCH /gifts/{uuid}/preview`
* `POST /gifts/{uuid}/confirm`
* `gifts[].offerCode` in order create/update payloads

These fields are present on:

* `GET /gifts/{uuid}`
* `GET /gifts`
* gift write responses
* gifts embedded in serialized order responses
* `offerCode`
* `offerTitle`
* `offerComparisons` (always `[]`)
* `offerIsCombination` (always `false`)
* `offer`
* `offers[]`
* `pricing.offerDiscount`

Base gift schema: [Gift Vouchers](/capabilities/gift-vouchers#endpoints).

## Extra Item Offers

Requires `octo/extras`.

Each serialized extra item (`booking.extraItems[]` and `booking.unitItems[].extraItems[]`) includes:

* `offerCode`
* `offerTitle`
* `offerComparisons` (always `[]`)
* `offerIsCombination` (always `false`)
* `offer`
* `offers[]`
* `pricing.offerDiscount`

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/offers" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Returns paginated supplier promotions serialized as the offer object above.

`GET /offers` returns supplier promotions sorted by position. Usability in this endpoint is not availability-specific; contextual usability is returned on availability/booking/gift/extra responses.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ]
}
```

### `AvailabilityBatchRequest`

```json
{
  "// ...rest of availability batch request object": "...",
  "offerCode": "SUMMER25"
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ]
}
```

### `AvailabilityCalendar`

```json
{
  "// ...rest of availability calendar object": "...",
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ],
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ]
}
```

### `AvailabilityCalendarBatchRequest`

```json
{
  "// ...rest of availability calendar batch request object": "...",
  "offerCode": "SUMMER25"
}
```

### `AvailabilityCalendarBatchRow`

```json
{
  "// ...rest of availability calendar batch row object": "...",
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ],
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ]
}
```

### `AvailabilityCalendarRequest`

```json
{
  "// ...rest of availability calendar request object": "...",
  "offerCode": "SUMMER25"
}
```

### `AvailabilityRequest`

```json
{
  "// ...rest of availability request object": "...",
  "offerCode": "SUMMER25"
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 22000,
        "retail": 20000,
        "net": 18000,
        "currency": "USD",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "Sales Tax",
            "shortDescription": "Local sales tax",
            "original": 2000,
            "retail": 1800,
            "net": 1600
          }
        ],
        "offerDiscount": {
          "retail": 2000,
          "net": 2000,
          "includedTaxes": [
            {
              "name": "Sales Tax",
              "shortDescription": "Local sales tax",
              "retail": 200,
              "net": 200
            }
          ]
        }
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "internalName": "Morning City Tour",
    "title": "Summer Promotion",
    "shortDescription": "Central departure with multilingual guide.",
    "code": "SUMMER25",
    "publicOfferId": "public_offer_id-example",
    "usable": true,
    "unusableReason": "Offer is not valid for the selected date.",
    "offerDiscount": {
      "retail": 2000,
      "net": 2000,
      "includedTaxes": [
        {
          "name": "Sales Tax",
          "shortDescription": "Local sales tax",
          "retail": 200,
          "net": 200
        }
      ]
    },
    "membershipBenefit": {
      "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "title": "VIP Member Discount",
      "description": "Reduced pricing for active members."
    },
    "tags": [
      "vip",
      "partner"
    ],
    "status": "CONFIRMED"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "internalName": "Morning City Tour",
      "title": "Summer Promotion",
      "shortDescription": "Central departure with multilingual guide.",
      "code": "SUMMER25",
      "publicOfferId": "public_offer_id-example",
      "usable": true,
      "unusableReason": "Offer is not valid for the selected date.",
      "offerDiscount": {
        "retail": 2000,
        "net": 2000,
        "includedTaxes": [
          {
            "name": "Sales Tax",
            "shortDescription": "Local sales tax",
            "retail": 200,
            "net": 200
          }
        ]
      },
      "membershipBenefit": {
        "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
        "title": "VIP Member Discount",
        "description": "Reduced pricing for active members."
      },
      "tags": [
        "vip",
        "partner"
      ],
      "status": "CONFIRMED"
    }
  ]
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ]
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "offerCode": "SUMMER25"
}
```

### `ExtraPricing`

```json
{
  "// ...rest of extra pricing object": "...",
  "offerDiscount": {
    "retail": 2000,
    "net": 2000,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "retail": 200,
        "net": 200
      }
    ]
  }
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ]
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "offerCode": "SUMMER25"
}
```

### `Money`

```json
{
  "// ...rest of money object": "...",
  "offerDiscount": {
    "retail": 2000,
    "net": 2000,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "retail": 200,
        "net": 200
      }
    ]
  }
}
```

### `Offer`

```json
{
  "// ...rest of offer object": "...",
  "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
  "tags": [
    "vip",
    "partner"
  ],
  "title": "Summer Promotion",
  "label": "Save 20%",
  "code": "SUMMER25",
  "description": "20% off selected departures this month.",
  "netDiscount": "FULL",
  "restrictions": {
    "minUnits": 1,
    "maxUnits": 10,
    "minTotal": 0,
    "maxTotal": 50000,
    "unitIds": [
      "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "6b65fd83-4a1f-4744-8f4a-c24d8d770f29"
    ]
  },
  "usable": true,
  "unusableReason": null
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "offerCombinations": [
    {
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "units": [
        {
          "unitId": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
          "quantity": 2
        }
      ],
      "offerCode": "SUMMER25"
    }
  ]
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "offers": [
    "offer-example"
  ]
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "offerCode": "SUMMER25",
  "offerTitle": "Summer Promotion",
  "offerIsCombination": true,
  "offerComparisons": [
    {
      "offerCode": "SUMMER25",
      "offerTitle": "Summer Promotion",
      "pricing": {
        "original": 2300,
        "retail": 2300,
        "net": 1610,
        "currency": "EUR",
        "currencyPrecision": 2,
        "includedTaxes": [
          {
            "name": "10%",
            "shortDescription": null,
            "original": 209,
            "retail": 209,
            "net": 146
          }
        ]
      },
      "offer": {
        "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
        "title": "Summer Promotion",
        "code": "SUMMER25"
      }
    }
  ],
  "offer": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "title": "Summer Promotion",
    "code": "SUMMER25"
  },
  "offers": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "code": "SUMMER25"
    }
  ]
}
```

### `Pricing`

```json
{
  "// ...rest of pricing object": "...",
  "offerDiscount": {
    "retail": 2000,
    "net": 2000,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "retail": 200,
        "net": 200
      }
    ]
  }
}
```

### `UnitPricing`

```json
{
  "// ...rest of unit pricing object": "...",
  "offerDiscount": {
    "retail": 2000,
    "net": 2000,
    "includedTaxes": [
      {
        "name": "Sales Tax",
        "shortDescription": "Local sales tax",
        "retail": 200,
        "net": 200
      }
    ]
  }
}
```


# Extras

Extras are upsell items that can be added to bookings and unit items

To use this capability, add `octo/extras` to your `Octo-Capabilities` header.

Extras are upsell items that can be configured either on the booking (option-level) or per unit item (unit-level). An extra might be a lunch package, fast track entrance, souvenir photo, or another optional add-on.

## Product Extras

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

Available extras are returned in the product response as:

* `option.extras[]` for booking-level extras
* `unit.extras[]` for unit-level extras

When combined with `octo/pricing` and `octo/content`, extra objects also include pricing and content fields.

Extra IDs are returned as `extra_<uuid>` in responses. For request payloads, both `extra_<uuid>` and raw UUID values are accepted.

For item-based products, item objects still include `extras`, but it is always an empty array.

## Extra Availability

This capability extends availability routes documented in [Availability](/octo-core/availability):

* `POST /availability`
* `POST /availability/calendar`
* `POST /availability/batch`
* `POST /availability/calendar/batch`

Extras do not require availability by themselves, but you can include extra quantities in availability queries to calculate total pricing.

For the normal case, availability requests use `extras[]` items with:

* `id`
* `quantity`

If an extra quantity exceeds configured limits, the API responds with:

* `EXTRAS_QTY_LIMIT` for booking-level extras
* `EXTRAS_UNIT_QTY_LIMIT` for unit-level extras

When used with `octo/pricing`, availability pricing includes both extra pricing breakdowns and totals.

`extraPricingFrom` is used instead of `extraPricing` on "from" payloads.

### Custom Retail Extras

A small number of extras may use reseller-supplied pricing. These extras are identified by `customRetail: true` on the extra object.

For custom retail extras:

* include `retail` in minor units on availability `extras[]`
* include `retail` in minor units on booking `extraItems[]`
* use `customRetailOptions` as suggested values if provided
* enforce `restrictions.minCustomRetail` and `restrictions.maxCustomRetail`

If a custom retail extra is used incorrectly, the API responds with:

* `EXTRAS_RETAIL_REQUIRED`
* `EXTRAS_RETAIL_BELOW_MINIMUM`
* `EXTRAS_RETAIL_ABOVE_MAXIMUM`

When `octo/pricing` is also enabled and a `currency` is selected, custom retail amounts are returned in that currency's minor units.

## Booking Reservation

This capability extends booking write routes documented in [Bookings](/octo-core/bookings#endpoints):

* `POST /bookings`
* `PATCH /bookings/{uuid}`

Use `extraItems[]` to reserve extras on bookings:

* booking-level extras: set `extraItems[]` on the booking object
* unit-level extras: set `extraItems[]` inside each `unitItems[]` object

When `extraItems` is present it must be an array.

For the normal case, each `extraItems[]` object contains:

* `extraId`
* optional `uuid`
* optional `resellerReference`

Send one `extraItems[]` object per reserved extra. If the same extra is reserved multiple times, repeat the same `extraId` in multiple array entries.

For custom retail extras, include `retail` on each `extraItems[]` object.

Booking and unit item responses both include `extraItems[]` with the same object schema.

When using the `octo/pricing` capability, booking and unit-item pricing totals include the sum of attached extra items. For purchase unit items, `extraItems` is always an empty array.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Option`

```json
{
  "// ...rest of option object": "...",
  "extras": [
    {
      "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "internalName": "Fast Track Entry",
      "reference": "fast_track_entry",
      "title": "Fast Track Entry",
      "customRetail": false,
      "customRetailOptions": [],
      "restrictions": {
        "required": false,
        "default": false,
        "idRequired": false,
        "minQuantity": 0,
        "maxQuantity": 2,
        "minCustomRetail": 0,
        "maxCustomRetail": null,
        "paxCount": 0,
        "accompaniedBy": [],
        "accompaniedByRatio": null,
        "accompaniedByRatioDenominator": null,
        "notAccompaniedBy": []
      }
    }
  ]
}
```

### `Unit`

```json
{
  "// ...rest of unit object": "...",
  "extras": [
    {
      "id": "4b8cb6fb-c7c5-4f0b-8ed9-c0fd7bb0aa26",
      "internalName": "Souvenir Photo",
      "reference": "souvenir_photo",
      "title": "Souvenir Photo",
      "customRetail": false,
      "customRetailOptions": [],
      "restrictions": {
        "required": false,
        "default": false,
        "idRequired": false,
        "minQuantity": 0,
        "maxQuantity": 1,
        "minCustomRetail": 0,
        "maxCustomRetail": null,
        "paxCount": 0,
        "accompaniedBy": [],
        "accompaniedByRatio": null,
        "accompaniedByRatioDenominator": null,
        "notAccompaniedBy": []
      }
    }
  ]
}
```

### `Option (Custom Retail Extra)`

```json
{
  "// ...rest of option object": "...",
  "extras": [
    {
      "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "internalName": "Guide Gratuity",
      "reference": "guide_gratuity",
      "title": "Guide Gratuity",
      "customRetail": true,
      "customRetailOptions": [500, 1000, 1500],
      "restrictions": {
        "required": false,
        "default": false,
        "idRequired": false,
        "minQuantity": 1,
        "maxQuantity": 1,
        "minCustomRetail": 500,
        "maxCustomRetail": 5000,
        "paxCount": 0,
        "accompaniedBy": [],
        "accompaniedByRatio": null,
        "accompaniedByRatioDenominator": null,
        "notAccompaniedBy": []
      }
    }
  ]
}
```

### `AvailabilityRequest`

The same `extras[]` selector fragment also applies to `AvailabilityCalendarRequest`, `AvailabilityBatchRequest`, and `AvailabilityCalendarBatchRequest`.

```json
{
  "// ...rest of availability request object": "...",
  "extras": [
    {
      "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "quantity": 2
    }
  ]
}
```

### `AvailabilityRequest (Custom Retail Extra)`

```json
{
  "// ...rest of availability request object": "...",
  "extras": [
    {
      "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "quantity": 1,
      "retail": 1500
    }
  ]
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "extraItems": [
    {
      "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "extraId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "resellerReference": "RES-BOOK-10045"
    },
    {
      "uuid": "a0d0f264-e244-461f-8612-4b175f8fa9e6",
      "extraId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "resellerReference": "RES-BOOK-10046"
    }
  ]
}
```

### `BookingWriteRequest (Custom Retail Extra)`

```json
{
  "// ...rest of booking write request object": "...",
  "extraItems": [
    {
      "uuid": "6a4f3d0f-d514-4db5-9c13-0d27d5f49a44",
      "extraId": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "retail": 1500,
      "resellerReference": "RES-BOOK-10047"
    }
  ]
}
```

### `BookingUnitItemWriteRequest`

```json
{
  "// ...rest of booking unit item write request object": "...",
  "extraItems": [
    {
      "uuid": "3f8b16ff-8e6d-49b4-a4ca-c0b4a137cc1b",
      "extraId": "4b8cb6fb-c7c5-4f0b-8ed9-c0fd7bb0aa26",
      "resellerReference": "RES-BOOK-10045-1"
    }
  ]
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "extraItems": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "resellerReference": "RES-BOOK-10045",
      "supplierReference": "SUP-BOOK-7782",
      "extraId": "extra_e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "status": "CONFIRMED"
    }
  ]
}
```

### `Booking (Custom Retail Extra)`

```json
{
  "// ...rest of booking object": "...",
  "extraItems": [
    {
      "id": "6a4f3d0f-d514-4db5-9c13-0d27d5f49a44",
      "uuid": "6a4f3d0f-d514-4db5-9c13-0d27d5f49a44",
      "extraId": "extra_3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "retail": 1500,
      "status": "CONFIRMED"
    }
  ]
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "extraItems": [
    {
      "id": "a0d0f264-e244-461f-8612-4b175f8fa9e6",
      "uuid": "3f8b16ff-8e6d-49b4-a4ca-c0b4a137cc1b",
      "extraId": "extra_4b8cb6fb-c7c5-4f0b-8ed9-c0fd7bb0aa26",
      "status": "CONFIRMED"
    }
  ]
}
```


# Packages

Adds package information showing sub-products within a booking

To use this capability, add `octo/packages` to your `Octo-Capabilities` header.

Packages are products that contain selectable sub-products ("includes"). You can sell package products without this capability, but enabling it exposes include-level product schema, include-aware availability, and include booking operations.

## Package Products

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

Each `option.packageIncludes[].includes[]` item follows the include object schema shown for product responses.

Base product schema: [Products](/octo-core/products). This page documents only package additions.

## Package Availability

This capability extends availability routes documented in [Availability](/octo-core/availability):

* `POST /availability`
* `POST /availability/calendar`

`/availability` responses add:

Each `packageAvailabilities[]` item is a full availability object (same fields as top-level availability) plus nested `packageAvailabilities`. `/availability/calendar` keeps the normal calendar schema and does not add `packageAvailabilities`.

Base availability schema: [Availability](/octo-core/availability).

## Package Booking

This capability extends booking write routes documented in [Bookings](/octo-core/bookings#endpoints):

* `POST /bookings`
* `PATCH /bookings/{uuid}`

Additional booking route variants that use the same package payload handling:

* `POST /bookings/{uuid}/confirm`

### Variant 1: Parent Booking With `packageBookings[]`

You can add include bookings while creating or updating the parent package booking by sending `packageBookings`.

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

### Variant 2: Direct Include Booking With `packageUuid`

You can create/update a single include booking directly by sending package context at the top level.

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

Booking responses include package-specific fields.

These are additive response fields on the base booking schema from [Bookings](/octo-core/bookings#endpoints).

You can target include booking UUIDs on standard booking endpoints (`GET`, `PATCH`, `POST .../confirm`, `POST .../cancel`, `POST .../extend`). Always check the returned `updatable` and `cancellable` flags to determine whether a specific include booking can be changed or cancelled. In `packageBookings[]`, child rows with hidden includes (or cancellation state mismatched to the parent row) are excluded from serialization.

## Listing Include Bookings

Include bookings are returned from `GET /bookings` (base route in [Bookings](/octo-core/bookings#endpoints)).

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "packageAvailabilities": [
    {
      "id": "9fa4425f-12ee-4cd9-8dd3-21509a7ec0c7",
      "localDateTimeStart": "2026-03-01T09:00:00-08:00",
      "localDateTimeEnd": "2026-03-01T12:00:00-08:00",
      "allDay": false,
      "available": true,
      "status": "AVAILABLE",
      "statusMessage": "Available",
      "utcCutoffAt": "2026-02-28T17:00:00Z",
      "openingHours": [
        {
          "from": "09:00",
          "to": "17:00"
        }
      ],
      "packageIncludeId": "11111111-2222-4333-8444-555555555555"
    }
  ]
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "packageAvailabilities": [
    {
      "id": "9fa4425f-12ee-4cd9-8dd3-21509a7ec0c7",
      "localDateTimeStart": "2026-03-01T09:00:00-08:00",
      "localDateTimeEnd": "2026-03-01T12:00:00-08:00",
      "allDay": false,
      "available": true,
      "status": "AVAILABLE",
      "statusMessage": "Available",
      "utcCutoffAt": "2026-02-28T17:00:00Z",
      "openingHours": [
        {
          "from": "09:00",
          "to": "17:00"
        }
      ],
      "packageIncludeId": "11111111-2222-4333-8444-555555555555"
    }
  ]
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "packageUuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
  "packageIncludeId": "package_include_id-example",
  "packageUnitItemUuid": "89fe0192-ddcd-430a-b285-e1396a4725d2"
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "packageIncludeId": "package_include_id-example",
  "packageUnitItemUuid": "89fe0192-ddcd-430a-b285-e1396a4725d2"
}
```

### `Option`

```json
{
  "// ...rest of option object": "...",
  "packageIncludes": [
    {
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
      "title": "Summer Promotion",
      "description": "Morning departure with central pickup included.",
      "includes": [
        {
          "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
          "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
          "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
          "required": true
        }
      ]
    }
  ]
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "packageAvailabilities": [
    {
      "id": "9fa4425f-12ee-4cd9-8dd3-21509a7ec0c7",
      "localDateTimeStart": "2026-03-01T09:00:00-08:00",
      "localDateTimeEnd": "2026-03-01T12:00:00-08:00",
      "allDay": false,
      "available": true,
      "status": "AVAILABLE",
      "statusMessage": "Available",
      "utcCutoffAt": "2026-02-28T17:00:00Z",
      "openingHours": [
        {
          "from": "09:00",
          "to": "17:00"
        }
      ],
      "packageIncludeId": "11111111-2222-4333-8444-555555555555"
    }
  ]
}
```

### `Product`

```json
{
  "// ...rest of product object": "...",
  "isPackage": true,
  "isPackagePass": true,
  "packageProduct": true
}
```


# Pickups

Adds pickup and dropoff functionality to the API

To use this capability, add `octo/pickups` to your `Octo-Capabilities` header.

This capability adds pickup/dropoff configuration to options, timed pickup/dropoff choices to availability responses, and pickup/dropoff selection fields on booking write/booking response objects.

## Routes

Product option fields are returned on:

* `GET /products`
* `GET /products/{productId}`

Availability fields are returned on:

* `POST /availability`
* `POST /availability/batch`

Booking write fields are accepted on:

* `POST /bookings`
* `PATCH /bookings/{uuid}`

## Behaviour

* If both `pickupPointId` and `pickupHotel` are sent, `pickupPointId` takes precedence.
* If both `dropoffPointId` and `dropoffHotel` are sent, `dropoffPointId` takes precedence.
* When `pickupHotel` is provided and no pickup point matches by name, the API geocodes/creates a hotel record and links it to the booking.
* When `dropoffHotel` is provided and no dropoff point matches by name, the API geocodes/creates a hotel record and links it to the booking.
* `pickupAddress` and `dropoffAddress` can be sent to improve hotel geocoding accuracy.
* Send `null` to clear existing values for pickup/dropoff booking fields.
* For custom dropoff products, availability-level `dropoffPoints` require an end time; for stop-based dropoff products, dropoffs are resolved by stop/date.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Option`

```json
{
  "// ...rest of option object": "...",
  "pickupAvailable": true,
  "pickupRequired": true,
  "pickupPoints": [
    {
      "id": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
      "name": "Union Square Pickup",
      "directions": "Meet outside the main entrance beside the red awning.",
      "address": "333 O'Farrell St, San Francisco, CA 94102",
      "latitude": 37.785452,
      "longitude": -122.408058,
      "googlePlaceId": "ChIJN1t_tDeuEmsRUsoyG83frY4",
      "street": "333 O'Farrell St",
      "postalCode": "94102",
      "locality": "San Francisco",
      "region": "California",
      "state": "CA",
      "country": "US",
      "localDateTime": null,
      "localDateTimeTo": null
    }
  ],
  "dropoffAvailable": true,
  "dropoffRequired": true,
  "dropoffPoints": [
    {
      "id": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
      "name": "Fisherman's Wharf Dropoff",
      "directions": "Dropoff opposite Pier 39 bus bay.",
      "address": "2500 Mason St, San Francisco, CA 94133",
      "latitude": 37.808673,
      "longitude": -122.409821,
      "googlePlaceId": "ChIJd8BlQ2B-j4ARk4A6A8sM5d0",
      "street": "2500 Mason St",
      "postalCode": "94133",
      "locality": "San Francisco",
      "region": "California",
      "state": "CA",
      "country": "US",
      "localDateTime": null,
      "localDateTimeTo": null
    }
  ]
}
```

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "pickupAvailable": true,
  "pickupRequired": true,
  "pickupPoints": [
    {
      "id": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
      "name": "Union Square Pickup",
      "localDateTime": "2026-05-14T08:30:00-07:00",
      "localDateTimeTo": "2026-05-14T08:45:00-07:00"
    }
  ],
  "dropoffAvailable": true,
  "dropoffRequired": true,
  "dropoffPoints": [
    {
      "id": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
      "name": "Fisherman's Wharf Dropoff",
      "localDateTime": "2026-05-14T13:30:00-07:00",
      "localDateTimeTo": null
    }
  ]
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "pickupAvailable": true,
  "pickupRequired": true,
  "pickupPoints": [
    {
      "id": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
      "name": "Union Square Pickup",
      "localDateTime": "2026-05-14T08:30:00-07:00",
      "localDateTimeTo": "2026-05-14T08:45:00-07:00"
    }
  ],
  "dropoffAvailable": true,
  "dropoffRequired": true,
  "dropoffPoints": [
    {
      "id": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
      "name": "Fisherman's Wharf Dropoff",
      "localDateTime": "2026-05-14T13:30:00-07:00",
      "localDateTimeTo": null
    }
  ]
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "pickupAvailable": true,
  "pickupRequired": true,
  "pickupPoints": [
    {
      "id": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
      "name": "Union Square Pickup",
      "localDateTime": "2026-05-14T08:30:00-07:00",
      "localDateTimeTo": "2026-05-14T08:45:00-07:00"
    }
  ],
  "dropoffAvailable": true,
  "dropoffRequired": true,
  "dropoffPoints": [
    {
      "id": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
      "name": "Fisherman's Wharf Dropoff",
      "localDateTime": "2026-05-14T13:30:00-07:00",
      "localDateTimeTo": null
    }
  ]
}
```

### `AvailabilityResourcesRequest`

```json
{
  "// ...rest of availability resources request object": "...",
  "pickupPointId": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
  "dropoffPointId": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46"
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "pickupRequested": true,
  "pickupPointId": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
  "pickupHotel": "Hilton Union Square",
  "pickupAddress": "333 O'Farrell St, San Francisco, CA 94102",
  "pickupHotelRoom": "1208",
  "pickupNotes": "Meet the guide by the hotel lobby.",
  "dropoffRequested": true,
  "dropoffPointId": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
  "dropoffHotel": "Hotel Riu Plaza Fisherman's Wharf",
  "dropoffAddress": "2500 Mason St, San Francisco, CA 94133",
  "dropoffNotes": "Drop-off at Fisherman's Wharf."
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "pickupRequested": true,
  "pickupPointId": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
  "pickupHotel": "Hilton Union Square, 333 O'Farrell St, San Francisco, CA 94102",
  "pickupHotelRoom": "1208",
  "pickupNotes": "Meet the guide by the hotel lobby.",
  "pickupPoint": {
    "id": "1cfe2c68-4a91-4df8-8d69-4b393d469caf",
    "name": "Union Square Pickup",
    "localDateTime": "2026-05-14T08:30:00-07:00",
    "localDateTimeTo": "2026-05-14T08:45:00-07:00"
  },
  "pickupDispatch": {
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "vehicle": "coach_12",
    "driver": "Alex Johnson",
    "guide": "Maria Santos",
    "area": "Downtown Loop",
    "notes": "Vehicle departs from Bay 4."
  },
  "dropoffRequested": true,
  "dropoffPointId": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
  "dropoffHotel": "Hotel Riu Plaza Fisherman's Wharf, 2500 Mason St, San Francisco, CA 94133",
  "dropoffNotes": "Drop-off at Fisherman's Wharf.",
  "dropoffPoint": {
    "id": "8d7a2fd8-f8f8-4e61-bbaf-5adac58f5d46",
    "name": "Fisherman's Wharf Dropoff",
    "localDateTime": "2026-05-14T13:30:00-07:00",
    "localDateTimeTo": "2026-05-14T13:45:00-07:00"
  },
  "dropoffDispatch": {
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "vehicle": "coach_12",
    "driver": "Alex Johnson",
    "guide": "Maria Santos",
    "area": "Downtown Loop",
    "notes": "Vehicle departs from Bay 4."
  }
}
```


# Custom Questions

Adds custom questions to order, booking, and unit-item flows

To use this capability, add `octo/questions` to your `Octo-Capabilities` header.

Custom questions let you collect additional guest information during booking and order flows. These questions are informational and do not change availability or pricing.

{% hint style="info" %}
Operations below use the `/octo` prefix.
{% endhint %}

## Question Definitions

Supported product routes:

* `GET /products`
* `GET /products/{productId}`

With this capability enabled, question definitions are added to option and unit schemas in product responses.

Questions are sorted by configured question position.

The same `questions` arrays are also returned on:

* `booking.option.questions[]`
* `booking.option.units[].questions[]`
* `booking.unitItems[].unit.questions[]`
* The same nested booking paths under `order.bookings[]`

### Question Object Fields

`inputType` is derived from options:

* `textarea`: no options
* `radio`: 1-5 options
* `select`: more than 5 options

Question objects are returned in the product and booking/order schemas from [Products](/octo-core/products), [Bookings](/octo-core/bookings#endpoints), and [Multi-Booking Cart](/capabilities/cart).

You should display booking-level questions once per booking, and ticket-level questions once per unit item.

Submit question answers before or on your final booking/order confirmation call so they are persisted with the confirmed records.

## Submit Answers On Booking Routes

Booking question fields are supported by these booking write routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

### Request Body Fields

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

## Submit Answers On Order Routes (`octo/cart` Required)

To submit order-level question answers, include both capabilities in the header:

* `octo/questions`
* `octo/cart`

Order question fields are supported by:

* `POST /orders`
* `PATCH /orders/{orderId}`
* `PATCH /orders/{orderId}/preview`
* `POST /orders/{orderId}/confirm`

## Returned Answer Fields

Booking objects include question answers on these routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`
* `POST /bookings/{uuid}/extend`
* `POST /bookings/{uuid}/cancel`
* `GET /bookings`
* `GET /bookings/{uuid}`

Order objects include question answers on these routes (`octo/cart` required):

* `POST /orders`
* `PATCH /orders/{orderId}`
* `PATCH /orders/{orderId}/preview`
* `POST /orders/{orderId}/confirm`
* `POST /orders/{orderId}/extend`
* `POST /orders/{orderId}/cancel`
* `DELETE /orders/{orderId}`
* `GET /orders`
* `GET /orders/{orderId}`

Each answer object field is included in the booking and order schemas.

Base schemas: [Bookings](/octo-core/bookings#endpoints) and [Multi-Booking Cart](/capabilities/cart).

`questionAnswers` arrays are returned in question position order and include all currently valid questions for that object, plus any existing persisted answers that are still attached.

{% hint style="info" %}
On update routes, omitting `questionAnswers` leaves existing answers unchanged.
{% endhint %}

{% hint style="info" %}
To clear an existing answer, send the same `questionId` with `value: null` (or empty string) in the relevant `questionAnswers` array.
{% endhint %}

{% hint style="info" %}
If a submitted `questionId` is unknown for that scope (`order`, `booking`, or `ticket`), the API returns `INVALID_QUESTION_ID` and includes `questionId` in the error body.
{% endhint %}

**Recommended flow:** create or fetch the booking/order first, then render your form from `questionAnswers` (and `unitItems[].questionAnswers` for unit items). Unanswered questions are returned with `value: null`.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `BookingUnitItemWriteRequest`

```json
{
  "// ...rest of booking unit item write request object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `Option`

```json
{
  "// ...rest of option object": "...",
  "questions": [
    {
      "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "title": "Summer Promotion",
      "required": true,
      "inputType": "select"
    }
  ]
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "questionAnswers": [
    {
      "questionId": "question_dietary_requirements",
      "value": "Vegetarian"
    }
  ]
}
```

### `Unit`

```json
{
  "// ...rest of unit object": "...",
  "questions": [
    {
      "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "title": "Summer Promotion",
      "required": true,
      "inputType": "select"
    }
  ]
}
```


# Waivers

Adds waiver templates and waiver submission fields to booking flows.

To use this capability, add `octo/waivers` to your `Octo-Capabilities` header.

This capability adds waiver definitions to products and adds waiver submission/status fields to booking write and booking response objects.

## Routes

Product waiver fields are returned on:

* `GET /products`
* `GET /products/{productId}`

Booking waiver write fields are accepted on:

* `POST /bookings`
* `PATCH /bookings/{uuid}`

Waiver status fields are returned on booking objects and booking unit-item objects in booking responses.

## Behaviour

* `product.waiverPer` determines where waiver inputs must be submitted.
* When `waiverPer` is `BOOKING`, submit waiver fields on the top-level booking request body.
* When `waiverPer` is `UNIT`, submit waiver fields on each `unitItems[]` object.
* `waiver.content` is markdown and can include field tags such as `-First Name-=__` or `-Email-=__("type":"email")`.
* Every field parsed from `waiver.content` is returned in `waiver.fields[]`.
* You can render those fields inline in the waiver form content, or render them separately using `waiver.fields[]`.
* `inputType: "signature"` should be rendered as a signature box.
* `inputType: "country"` should be rendered as a country dropdown.
* For `country`, submit the selected value as an ISO 3166-1 alpha-2 code (for example `GB`, `US`).
* Standard waiver submission requires `waiverId` and `waiverFieldValues`.
* `waiverFile` is optional and can be sent at booking level or unit-item level. Use a PDF data URI (`data:application/pdf;base64,...`) if you want to save a rendered waiver copy.
* If `waiverId` is sent at the wrong level, the API returns `WAIVER_ON_BOOKING_ONLY` or `WAIVER_ON_TICKET_ONLY`.
* `waiverId` must match one of `product.waivers[]`; otherwise the API returns `INVALID_WAIVER_ID`.
* `waiverFieldValues` must be an array and each record must include `fieldId`.
* `waiversComplete` indicates whether waiver requirements are complete for the booking/unit item.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Product`

```json
{
  "// ...rest of product object": "...",
  "waiverPer": "UNIT",
  "waiverRequired": true,
  "waivers": [
    {
      "id": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
      "title": "Participant Release and Assumption of Risk",
      "shortDescription": "Required before tour participation.",
      "content": "I acknowledge and accept the risks of participation.\n\n-First Name-=__\n-Email-=__(\"type\":\"email\")\n-Signature-=__(\"type\":\"signature\")\n-Country-=__(\"type\":\"country\")",
      "fields": [
        {
          "id": "first_name",
          "internalName": "First Name",
          "title": "First Name",
          "shortDescription": null,
          "required": true,
          "inputType": "text",
          "maxLength": null,
          "selectOptions": []
        },
        {
          "id": "email",
          "internalName": "Email",
          "title": "Email",
          "shortDescription": null,
          "required": true,
          "inputType": "email",
          "maxLength": null,
          "selectOptions": []
        },
        {
          "id": "signature",
          "internalName": "Signature",
          "title": "Signature",
          "shortDescription": null,
          "required": true,
          "inputType": "signature",
          "maxLength": null,
          "selectOptions": []
        },
        {
          "id": "country",
          "internalName": "Country",
          "title": "Country",
          "shortDescription": null,
          "required": true,
          "inputType": "country",
          "maxLength": null,
          "selectOptions": []
        }
      ]
    }
  ]
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "waiverId": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
  "waiverFieldValues": [
    {
      "fieldId": "first_name",
      "value": "Jane"
    },
    {
      "fieldId": "email",
      "value": "jane.doe@goldengatetours.com"
    },
    {
      "fieldId": "signature",
      "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    },
    {
      "fieldId": "country",
      "value": "US"
    }
  ]
}
```

### `BookingWriteRequest (Offline/In-Person)`

```json
{
  "// ...rest of booking write request object": "...",
  "waiverId": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
  "waiverFieldValues": [
    {
      "fieldId": "first_name",
      "value": "Jane"
    },
    {
      "fieldId": "email",
      "value": "jane.doe@goldengatetours.com"
    },
    {
      "fieldId": "signature",
      "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    },
    {
      "fieldId": "country",
      "value": "US"
    }
  ],
  "waiverFile": "data:application/pdf;base64,JVBERi0xLjQKJcTl8uXr..."
}
```

### `BookingUnitItemWriteRequest`

```json
{
  "// ...rest of booking unit item write request object": "...",
  "waiverId": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
  "waiverFieldValues": [
    {
      "fieldId": "first_name",
      "value": "Jane"
    },
    {
      "fieldId": "email",
      "value": "jane.doe@goldengatetours.com"
    },
    {
      "fieldId": "signature",
      "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    },
    {
      "fieldId": "country",
      "value": "US"
    }
  ],
  "waiverFile": "data:application/pdf;base64,JVBERi0xLjQKJcTl8uXr..."
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "waiverId": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
  "waiverFileUrl": "https://api.ventrata.com/uploads/waivers/waiver_booking_10045.pdf",
  "waiverFieldValues": [
    {
      "fieldId": "first_name",
      "value": "Jane"
    },
    {
      "fieldId": "email",
      "value": "jane.doe@goldengatetours.com"
    },
    {
      "fieldId": "signature",
      "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    },
    {
      "fieldId": "country",
      "value": "US"
    }
  ],
  "waiversComplete": true
}
```

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "waiverId": "6d8c49eb-d6d3-4f03-a242-6f5f95f4d56f",
  "waiverFileUrl": "https://api.ventrata.com/uploads/waivers/waiver_booking_10045.pdf",
  "waiverFieldValues": [
    {
      "fieldId": "first_name",
      "value": "Jane"
    },
    {
      "fieldId": "email",
      "value": "jane.doe@goldengatetours.com"
    },
    {
      "fieldId": "signature",
      "value": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
    },
    {
      "fieldId": "country",
      "value": "US"
    }
  ],
  "waiversComplete": true
}
```


# Resources

Adds the ability to see and edit resource allocations

To use this capability, add `octo/resources` to your `Octo-Capabilities` header.

Resources are allocated to each booking and determine availability for resource-based products (for example vehicles, rooms, or seat maps).

{% hint style="info" %}
Even for products that rely on resources, this capability is optional. If you do not provide resource selections, allocations are assigned automatically.
{% endhint %}

{% hint style="info" %}
Operations below use the `/octo` prefix.
{% endhint %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability/resources" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/availability/resources" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Returns resources grouped by `resourceGroupId` for a single `availabilityId`.

### Request Fields

For `GET`, send these as query parameters. For `POST`, send them in the JSON body.

### Response Fields

Response is an array of resource-group objects.

#### Seat Object

Used in `resource.seats[]`, `availableSeats[]`, `selectedSeats[]`, and booking allocation `seats[]`.

#### Seller Object (driver/guide)

See the resource operations above for response payload examples.

{% hint style="info" %}
Each booking must allocate enough resources from every required resource group. When `resourceGroup.split` is `false`, one resource in that group must cover the full requested size.
{% endhint %}

## Booking Reservation / Update

Resource allocations are accepted on all booking write routes that call booking create/update logic:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

{% hint style="info" %}
Request `resourceAllocations[].paxCount` and `resourceAllocations[].seatIds` are ignored by current booking write parsing. Pax and seat assignment are computed server-side from allocation/unit data.
{% endhint %}

{% hint style="info" %}
When `resourceAllocations` is present and non-empty, allocations not included in the submitted list are removed from the booking. Sending `resourceAllocations: []` is currently a no-op (existing allocations remain unchanged).
{% endhint %}

`resourceAllocations` is appended to serialized booking objects on:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`
* `GET /bookings/{uuid}`
* `GET /bookings`
* `POST /bookings/{uuid}/cancel`
* `POST /bookings/{uuid}/extend`

The same booking-response additions are also present in any other response that serializes a booking object.

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

## Added Availability Field

This capability also adds `hasResources` to serialized availability objects returned by:

* `POST /availability`
* `POST /availability/batch`
* `booking.availability` inside serialized booking responses

Base availability schema: [Availability](/octo-core/availability).

{% hint style="info" %}
`hasResources` is added to `/availability` responses, not `/availability/calendar` responses.
{% endhint %}

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "hasResources": true
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "hasResources": true
}
```

### `AvailabilityResourcesRequest`

```json
{
  "// ...rest of availability resources request object": "...",
  "resourceAllocations": [
    {
      "resourceId": "resource_coach_12"
    }
  ]
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "resourceAllocations": [
    {
      "resourceGroupId": "resource_group_front_row",
      "resourceGroup": {
        "title": "Front Row"
      },
      "resourceId": "resource_coach_12",
      "resource": {
        "title": "Coach 12"
      },
      "seatIds": [
        "seat_one",
        "seat_two"
      ],
      "seats": [
        {
          "row": "A",
          "column": "4"
        }
      ],
      "paxCount": 2
    }
  ]
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "resourceAllocations": [
    {
      "resourceId": "resource_coach_12"
    }
  ]
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "hasResources": true
}
```


# Rentals

Adds rental duration selection and rental metadata to OCTO endpoints.

To use this capability, add `octo/rentals` to your `Octo-Capabilities` header.

Rentals adds duration selection for rental products and exposes rental metadata on product, option, and booking responses.

{% hint style="info" %}
Operations below use the `/octo` prefix.
{% endhint %}

## Rental Product Data

This capability extends product routes documented in [Products](/octo-core/products):

* `GET /products`
* `GET /products/{productId}`

### Rental Duration Object

Used by `option.rentalDurations[]` and `booking.rentalDuration`.

Base product schema: [Products](/octo-core/products).

{% hint style="info" %}
Always use ids returned by `option.rentalDurations[]`. Unsupported duration units return `INVALID_RENTAL_DURATION_ID`.
{% endhint %}

## Rental Availability

This capability extends availability routes documented in [Availability](/octo-core/availability):

* `POST /availability`
* `POST /availability/calendar`
* `POST /availability/batch`
* `POST /availability/calendar/batch`

### Request Fields Added by Rentals

Base availability schema: [Availability](/octo-core/availability).

{% hint style="info" %}
Rentals does not add new availability response fields. The selected duration is applied to availability and pricing calculation.
{% endhint %}

## Rental Booking

The same `rentalDurationId` request field is supported on all booking write routes that use `create_booking`:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

### Request Field

Base booking schema: [Bookings](/octo-core/bookings#endpoints).

### Added Booking Response Fields

These are additive response fields on the base booking schema from [Bookings](/octo-core/bookings#endpoints).

{% hint style="info" %}
These booking fields are returned on booking write routes above and booking read/cancel/extend routes that serialize bookings (`GET /octo/bookings`, `GET /octo/bookings/:uuid`, `POST /octo/bookings/:uuid/cancel`, `POST /octo/bookings/:uuid/extend`).
{% endhint %}

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `AvailabilityBatchRequest`

```json
{
  "// ...rest of availability batch request object": "...",
  "rentalDurationId": "rental_duration_2h"
}
```

### `AvailabilityCalendarBatchRequest`

```json
{
  "// ...rest of availability calendar batch request object": "...",
  "rentalDurationId": "rental_duration_2h"
}
```

### `AvailabilityCalendarRequest`

```json
{
  "// ...rest of availability calendar request object": "...",
  "rentalDurationId": "rental_duration_2h"
}
```

### `AvailabilityRequest`

```json
{
  "// ...rest of availability request object": "...",
  "rentalDurationId": "rental_duration_2h"
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "rentalDurationId": "rental_duration_2h",
  "rentalDuration": {
    "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
    "duration": "2",
    "durationAmount": 220.0,
    "durationUnit": "HOUR",
    "title": "Summer Promotion",
    "description": "Morning departure with central pickup included."
  }
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "rentalDurationId": "rental_duration_2h"
}
```

### `Option`

```json
{
  "// ...rest of option object": "...",
  "rentalDurations": [
    {
      "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "title": "Summer Promotion",
      "duration": "2",
      "durationAmount": 220.0
    }
  ]
}
```

### `Product`

```json
{
  "// ...rest of product object": "...",
  "isRental": true
}
```


# Redemption

Redeem tickets and bookings by reference or barcode

To use this capability, add `octo/redemption` to your `Octo-Capabilities` header.

This capability allows supplier/operator connections to look up bookings and tickets, redeem/unredeem them, and mark them as no-show by redemption code.

All paths below are public `/octo` routes.

The OCTO API prefix is `/octo`.

## Endpoint Summary

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/lookup" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Lookup by `reference`, `email`, or `mobile`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/redeem" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Redeem one or more redemption codes.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/redeem" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Cancel redemption (unredeem) for one or more redemption codes.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/noshow" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Mark one or more redemption codes as no-show.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/noshow" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Route variant currently mapped to the same action as `DELETE /redemption/redeem`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/credentials" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Unauthenticated API key resolution by lookup input.

Use `GET /products` to cache available product/option/unit metadata used by redemption responses (see [Products](/octo-core/products#list-products)).

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/lookup" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Find matching bookings/tickets for a scanned code/reference, email, or mobile.

**Query Parameters**

Provide at least one of `reference`, `email`, or `mobile`.

**Response**

Returns `array[Redemption Object]` (see [Redemption Object](#redemption-object)).

* Lookup can return multiple results for package products with redeemable inclusions.
* Each result includes `redemptionCode`, `redeemable`, `unredeemableReason`, and `unredeemableReasonCode`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/redeem" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/redeem" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Both routes use the same request shape and response schema.

**Request Body / Query Parameters**

If `redemptionCode` is an array, the response is `array[Redemption Object]` in input order. Otherwise, the response is a single `Redemption Object`.

When redemption is rejected as not redeemable, a `400 BAD_REQUEST` can include both `redemptionCode` and `redemptionErrorCode` in the response body.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/noshow" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/noshow" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

**Request Body / Query Parameters**

`POST /redemption/noshow` returns a redemption object/object-array with no-show state (for example `status: "NO_SHOW"`, `utcNoshowedAt` set).

`DELETE /redemption/noshow` is currently wired to the same controller path as `DELETE /redemption/redeem`, so behavior and response shape match cancel-redemption/unredeem.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/redemption/credentials" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

This endpoint is unauthenticated and selects the first API key that can successfully resolve the provided lookup input.

**Request Body Parameters**

Provide at least one of `reference`, `email`, or `mobile`.

**Response**

## Redemption Object

Lookup, redeem, and no-show responses serialize via `serialize_redemption(...)`, which wraps `serialize_booking(...)` and ticket/voucher helpers.

### Top-level fields

For full core object details of `product`, `option`, `availability`, and contact/user/reseller-style objects, see [Bookings](/octo-core/bookings#booking-reservation) and linked core schemas.

### Additional serialization notes

* When a redemption code resolves at ticket level, `unitItems` is reduced to that ticket only, `voucher` is set to that ticket object, and overlapping root fields are overwritten with ticket-level values.
* `serialize_item(...)` adds `scans: []` on serialized item units (for example `option.units[]` entries of type `OTHER`).

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `BookingUnitItem`

```json
{
  "// ...rest of booking unit item object": "...",
  "scans": [
    {
      "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "status": "CONFIRMED",
      "utcScannedAt": "2026-05-14T13:00:00Z",
      "seller": {
        "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
        "name": "Morning City Tour",
        "reference": "REF-2026-001",
        "tags": [
          "vip",
          "partner"
        ]
      }
    }
  ]
}
```


# Self-Service Mapping

Send a list of listings to get the supplier to map them themselves

To use this capability, add `octo/mappings` to your `Octo-Capabilities` header.

This capability allows you to send a "mapping sheet" of products that you need to map. This is then given to the supplier in a user-friendly form they can select which product each item maps to in their Ventrata system. Once the mapping has been set a webhook URL is called to notify your system of the change.

The mappings endpoints are available under `/octo`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/mappings" method="put" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Body must be a JSON array of mapping rows.

See the `PUT /mappings` operation above for request schema examples.

`resellerReference` is required on each item. Items are upserted by `resellerReference`, and any existing mappings not included in the array are removed.

Whenever a product in your system for this supplier has been changed, updated or deleted, you should repeat this request with all mappings. `PUT` synchronizes the full set for the connection.

After you make the request and new mappings are added, Ventrata sends a notification to the supplier to complete them.

Once the supplier chooses a product and option for a mapping, Ventrata sends a `POST` request to the URL provided in `webhookUrl` for that mapping row. The webhook body follows the mapping object schema and includes resolved `productId`, `optionId`, and `unitId` values.

The `unitId` and `optionId` will be null in the webhook request body if we set `unitRequired` and `optionRequired` to false respectively on the original mappings request.

Your response to this request must be `2XX` (for example `200 OK`), otherwise we retry until we receive a `2XX` response.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/mappings" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

#### Query Parameters

If both `productId` and `productIds[]` are provided, `productId` is used. If both `optionId` and `optionIds[]` are provided, `optionId` is used. Use repeated query keys for arrays, for example `productIds[]=id1&productIds[]=id2`. `DEFAULT` on `optionId`/`optionIds[]` filters for mappings without a stored option.

`optionId` and `unitId` may be `null` when no mapping has been selected yet, or when `optionRequired` / `unitRequired` is `false`.

## Booking and Availability Responses

When this capability is enabled, booking and availability responses include a `mappings` field. The array contains mappings for the response product/option combination.

* Booking responses include `booking.mappings`.
* Availability responses include `availability[].mappings`.

Each `mappings[]` item uses the same schema as the mappings list response.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Availability`

```json
{
  "// ...rest of availability object": "...",
  "mappings": [
    {
      "resellerReference": "RES-BOOK-10045",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "resellerStatus": "CONFIRMED"
    }
  ]
}
```

### `AvailabilityBatchRow`

```json
{
  "// ...rest of availability batch row object": "...",
  "mappings": [
    {
      "resellerReference": "RES-BOOK-10045",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "resellerStatus": "CONFIRMED"
    }
  ]
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "mappings": [
    {
      "resellerReference": "RES-BOOK-10045",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "resellerStatus": "CONFIRMED",
      "resellerProduct": "grand-canyon-day-tour",
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "unitId": "unit_adult",
      "optionRequired": true,
      "unitRequired": true,
      "validityDays": 2,
      "webhookUrl": "https://www.city-sightseeing.com"
    }
  ]
}
```

### `MappingUpsertRequest`

```json
{
  "// ...rest of mapping upsert request object": "...",
  "mappings": [
    {
      "resellerReference": "RES-BOOK-10045",
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b"
    }
  ]
}
```

### `PackageAvailability`

```json
{
  "// ...rest of package availability object": "...",
  "mappings": [
    {
      "resellerReference": "RES-BOOK-10045",
      "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
      "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
      "resellerStatus": "CONFIRMED"
    }
  ]
}
```


# Multi-Booking Cart

Sell more than one booking together in a cart

To use this capability, add `octo/cart` to your `Octo-Capabilities` header.

This capability lets you create multiple bookings from the same supplier in a single cart. In Ventrata, a cart is called an order, and this document uses that term.

All order paths below are public `/octo` routes.

## Reserve Booking in an Order

This capability extends booking write routes from [Bookings](/octo-core/bookings#endpoints) so you can pass `orderId` to attach a booking to an existing order (or omit `orderId` to auto-create one).

## Order Fields Returned on Booking and Gift Responses

When using `octo/cart`, the booking response (and gift response when using `octo/gifts`) includes additional order-level fields.

When using this capability, if you omit `orderId` from the initial request, Ventrata creates a new order automatically and returns `orderId` in the response. You can then reuse `orderId` in future booking requests to attach bookings to the same order.

You can also provide `orderId` on `POST /gifts` (when `octo/gifts` is enabled) to attach a gift voucher to an existing order.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Field definitions are included in the operation schemas above.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}/preview" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}/extend" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}/confirm" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

If you're using the cart capability and want to set a `resellerReference` you should do so as a [booking update](/octo-core/bookings#booking-update) as there are no reseller references on the order level.

Once you call this method, each of the bookings and gifts contained within the order will be confirmed too.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

This endpoint performs order-level cancellation. Equivalent behavior is available via `POST /orders/{orderId}/cancel`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}/cancel" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

At least one of the filter groups above is required for `GET /orders`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/orders/{orderId}/notify" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

`POST /orders/{orderId}/notify` returns `200 OK` with an empty response body.

Order invoice and voucher delivery URLs are returned directly on serialized order/booking objects.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "orderId": "ord_20260514_9f3c21",
  "orderReference": "ORDER-2026-0514-1001",
  "orderInvoicePdfUrl": "https://www.city-sightseeing.com",
  "primary": true
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "orderId": "ord_20260514_9f3c21"
}
```

### `Error`

```json
{
  "// ...rest of error object": "...",
  "orderId": "ord_20260514_9f3c21"
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "orderId": "ord_20260514_9f3c21",
  "orderReference": "ORDER-2026-0514-1001",
  "orderInvoicePdfUrl": "https://www.city-sightseeing.com",
  "primary": true
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "orderId": "ord_20260514_9f3c21"
}
```


# Gift Vouchers

Allows you to sell and redeem gift vouchers

To use this capability, add `octo/gifts` to your `Octo-Capabilities` header.

Gift vouchers allow you to sell fixed value monetary amounts in the form of a gift card which can be redeemed later as a form of payment against a new order.

All paths below are under `/octo`.

## Endpoints

Gift voucher routes are documented below.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

The UUID on the request body is optional but recommended if you're requesting from a source of poor network connectivity. If the connection fails or you do not receive a response, you can repeat the same request with the same UUID and it will respond with the same gift object without duplicating the gift voucher.

The gift voucher object returned by all gift endpoints in this section is also used in order responses under `gifts[]`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

You can update a gift voucher before and after it has been confirmed as long as it has not been redeemed and is still updateable. To check this, use the `gift.updatable` field.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}/preview" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}/confirm" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

See the confirmation operation above for request examples.

Once the gift is confirmed and deliverable, voucher delivery options are populated on the response.

The `deliveryValue` for `QRCODE` can be typed online to redeem the gift voucher, and URL-based formats can be shared directly with the guest.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}/cancel" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Note you can only cancel a gift voucher if `gift.cancellable` is true.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}/extend" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

This endpoint will fetch the gift voucher with the provided UUID from the system.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

When using this endpoint you must include one of the following filters:

* `resellerReference`
* `supplierReference`
* `utcCreatedAtStart` and `utcCreatedAtEnd`
* `utcUpdatedAtStart` and `utcUpdatedAtEnd`
* `contactEmailAddress`

If no valid filter is provided the API returns `GIFTS_FIELDS_REQUIRED`.

Results are paginated.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/gifts/{uuid}/notify" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Gift voucher delivery URLs (PDF/PNG/PKPASS/Google Wallet) are returned directly in `voucher.deliveryOptions`.

With a confirmed gift code, redeem by adding `giftPayment` to booking/order/gift write requests.

`giftPayment` is accepted on the write flows documented in:

* [Bookings](/octo-core/bookings#endpoints)
* [Multi-Booking Cart](/capabilities/cart)
* [Gift Vouchers](#endpoints)

Request payload fields are included in the operation schema above.

If the code is valid, currency matches the order currency, and the gift card has available credit then payment is applied.

If `giftPayment` is present but `code` is omitted/blank, existing non-voided gift payment transactions on the order are voided.

Order responses include the same `giftPayment` object and also include gift objects under `gifts[]`.

The gift card may have enough credit to cover the full order, in which case you can confirm immediately. Otherwise, add a card payment as well (see [Card Payments](/capabilities/card-payments)).

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "giftPayment": {
    "giftCode": "GIFT-2026-0001",
    "code": "SUMMER25",
    "amount": 220.0,
    "currency": "USD"
  }
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "giftPayment": {
    "code": "GIFT-2026-0001"
  }
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "giftPayment": {
    "code": "GIFT-2026-0001"
  }
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "giftPayment": {
    "code": "GIFT-2026-0001"
  }
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "gifts": [
    {
      "uuid": "gift_20260514_ba21f7",
      "status": "CONFIRMED",
      "currency": "USD",
      "id": "89fe0192-ddcd-430a-b285-e1396a4725d2"
    }
  ],
  "giftPayment": {
    "code": "GIFT-2026-0001"
  }
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "gifts": [
    {
      "amount": 100.0,
      "currency": "USD"
    }
  ]
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "gifts": [
    {
      "amount": 100.0,
      "currency": "USD"
    }
  ]
}
```


# Online Check-in

Just like with an airline, except for tours and activities

To use this capability, add `octo/checkin` to your `Octo-Capabilities` header.

Some products require online check-in after booking confirmation and before the guest is allowed to use their tickets. This is typically the case when:

* The product has waivers that must be signed by each guest.
* The product has required questions that need answering (such as dietary requirements).
* The product is a multi-part package where each part needs a travel date and time chosen.

If the check-in process is skipped, the guest can still complete check-in on arrival, but it may delay entry.

All paths below are public `/octo` routes.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/checkin/lookup" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

**Request Body / Query Parameters**

Provide one of `email`, `mobile`, or `reference`.

* `reference` must be at least 3 characters unless it is a UUID.
* For email/mobile lookups, the first request (without `verification`) sends a 6-digit verification code and returns `verified: false`.
* For reference lookups, `verification` should be the guest name used for identity verification.
* If both `status` and `statuses` are sent, `status` is used.

**Response fields**

**Accepted `status` / `statuses` values (booking lookup)**

* `REDEEMED`
* `NO_SHOW`
* `ON_HOLD`
* `CANCELLED`
* `EXPIRED`
* `PENDING`
* `REJECTED`
* `REBOOKED`
* `QUOTE`
* `CONFIRMED`

If no booking matches, the API returns `400 Bad Request` (for example `BOOKING_NOT_FOUND`).

## Route Variants Using Nested `checkin`

After lookup, reuse the same verified check-in context on other endpoints by sending a nested `checkin` object.

For `GET` requests use query params like `checkin[email]=...`. For JSON request bodies use a top-level `checkin` object.

For gift-scoped lookups, `PENDING`, `REJECTED`, and `REBOOKED` are not valid status values.

### Endpoint coverage

* `GET /bookings/{uuid}`
* `GET /gifts/{uuid}`
* `GET /orders/{orderId}`
* `GET /products`

Base schemas are documented in [Bookings](/octo-core/bookings), [Gift Vouchers](/capabilities/gift-vouchers), [Multi-Booking Cart](/capabilities/cart), and [Products](/octo-core/products).

## Response Fields Added By This Capability

This capability augments serialized booking and order responses.

All booking fields from [Bookings](/octo-core/bookings) are still returned, with the additional fields below.

### Order fields

When an order is serialized (for example with `octo/cart` endpoints), this capability adds check-in fields.

Nested `order.bookings[]` objects continue to include the booking fields above (`checkedIn`, `checkinAvailable`, `checkinUrl`). This capability does not add new check-in-specific fields to gift objects.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "checkedIn": true,
  "checkinAvailable": true,
  "checkinUrl": "https://checkin.city-sightseeing.com/booking/89fe0192"
}
```


# Card Payments

Take card payments through the API

To use this capability, add `octo/cardPayments` to your `Octo-Capabilities` header.

This capability allows you to accept card payments via the API.

Gateway IDs returned/accepted in source are:

* `adyen`
* `external`

## Endpoints

All paths below are under `/octo`.

This capability extends booking/order/gift write flows and related read flows documented in:

* [Bookings](/octo-core/bookings#endpoints)
* [Multi-Booking Cart](/capabilities/cart)
* [Gift Vouchers](/capabilities/gift-vouchers)

List routes intentionally omit `cardPayment`/`returnUrl`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/card\_payments/{cardPaymentId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Validation rules from source:

* `cardPayment.source` must be one of `POS`, `ECOM`, `MOTO` (`GATEWAY_INVALID_SOURCE` otherwise).
* `cardPayment.currency` must match the order currency (`GATEWAY_CURRENCY_MISMATCH` otherwise).
* If `cardPayment.cardId` is supplied it must reference a reusable card on the selected gateway (`INVALID_CARD_ID` otherwise).
* If an explicit gateway is supplied and does not match the resolved gateway, source raises `GATEWAY_MISMATCH`.

## Response Fields

All card payment request/response fields (including `reusableCards[]` and gateway payloads) are included on the card payment schemas in this page.

Notes:

* `adyen` can return `{}` when `amount <= 0`.
* The card payment lookup endpoint returns cached card payment JSON (up to 1 hour) and is only available when the card payment object was created with a `returnUrl`.

## Adyen Gateway

{% embed url="<https://docs.adyen.com/online-payments/build-your-integration?platform=Web&integration=Drop-in&version=5.43.0>" %}
Adyen Drop-in Integration Docs
{% endembed %}

`session` is `null` until you set a `returnUrl` (for `ECOM` payments).

When you confirm/replay payment, source accepts:

* `adyen.sessionId`
* `adyen.sessionResult` (optional with sessionId)
* `adyen.pspReference`
* `adyen.paymentMethod`
* `adyen.channel`

For Adyen session creation, channel is resolved from the `adyen-channel` request header first, then `cardPayment.adyen.channel`, then defaults to `Web`.

Most integrations send this payload on the booking/order/gift confirm route that finalizes payment.

If Ventrata has not yet received the webhook notification from Adyen then you may receive a `PAYMENT_PENDING` error code. Repeat the request. If the payment is refused, you get a `BAD_REQUEST` error with the reason in `errorMessage`.

## External Gateway

The external gateway lets you register a virtual card payment taken on an external processor.

`external.approved` defaults to `true` when omitted. For external payload processing, source requires at least one of `notes`, `amount`, `currency`, or `cancel` to be present.

## Reusable Cards

Reusable card fields are included in the `ReusableCard` schema.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "cardPayment": {
    "status": "CONFIRMED",
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "cardPaymentId": "cp_20260514_42ad10",
    "gateway": "adyen",
    "source": "POS",
    "paid": 2200,
    "totalPaid": 2200,
    "totalRefunded": 0,
    "paidSurcharge": 0,
    "balance": 0,
    "surcharge": 0,
    "outstandingBalance": 0,
    "amount": 2200,
    "currency": "USD",
    "currencyPrecision": 2,
    "reusableCards": [
      {
        "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
        "brand": "visa",
        "bin": "411111",
        "last4": "1111"
      }
    ],
    "adyen": {
      "environment": "test",
      "clientKey": "test_client_key_123",
      "session": {
        "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
        "sessionData": "session_data_payload"
      },
      "countryCode": "US"
    },
    "external": {},
    "provider": "adyen",
    "providerReference": "PROV-REF-2026-001",
    "createdAt": "2026-05-14T13:00:00Z"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `Error`

```json
{
  "// ...rest of error object": "...",
  "cardPaymentId": "cp_20260514_42ad10"
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "cardPayment": {
    "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
    "gateway": "external",
    "status": "PENDING"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "cardPayment": {
    "gateway": "external",
    "external": {
      "approved": true
    }
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "cardPayment": {
    "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
    "gateway": "adyen",
    "status": "PENDING"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "cardPayment": {
    "gateway": "adyen"
  },
  "returnUrl": "https://checkout.city-sightseeing.com/return"
}
```


# Memberships

Exposes Ventrata membership capabilities to OCTO.

This capability allows member benefits to be redeemed when making new bookings.

To use this capability, add `octo/memberships` to your `Octo-Capabilities` header.

All paths below are public `/octo` routes.

## Member Login

First, provide a member login entry point in your interface (for example a "Member Login" button) and collect one of the following identifiers:

* **Email** We send a verification code to the customer's email, and you repeat that code in a follow-up request to verify identity.
* **Mobile** We send a verification code to the customer's mobile number, and you repeat that code in a follow-up request to verify identity.
* **Reference** If a booking exists, we ask for the customer's last name to verify identity.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/memberships/lookup" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

**Request Body / Query Parameters**

You should send either `email`, `mobile`, or `reference`. If using `reference`, it must be at least 3 characters.

See the lookup operation above for request/response schemas.

The response returns `400 Bad Request` if no memberships are found. Otherwise, it returns a message with `"verified": false`; prompt for the verification code and repeat the request with that value.

For `reference`, the verification value is the guest's last name. For `email` and `mobile`, the verification value is a 6-digit code sent to the provided email address or mobile number.

Once you repeat the request, including the `verification` field with the verification code, it will verify the member and return a list of memberships that they have.

If multiple memberships are returned, provide an interface to pick one, using `title` and/or `contact` to differentiate between them.

## Membership Object For Requests

After lookup, include a `membership` object on membership-aware requests (or `membership[...]` query parameters for `GET` endpoints).

`membership[id]` is required.

Also include one of `membership[email]`, `membership[mobile]`, or `membership[reference]`, together with `membership[verification]`.

If using `membership[mobile]`, include `membership[country]`.

## Product Benefits

Memberships can have multiple benefits. Once you have logged in and selected a membership, include a membership object in each request.

Product benefits are returned on base product routes:

* `GET /products/{productId}`
* `GET /products`

Call the product endpoint and include the membership object as query parameters.

You should repeat the same identifier (`email`, `mobile` or `reference`) and `verification` from the login step, and include `id` to specify which membership to apply.

Base product schema: [Products](/octo-core/products).

Memberships with product benefits add additional units to the list. You can identify units that belong to a membership benefit via the `membershipBenefit` object, which is otherwise `null`.

If you're rendering this on a page showing the available units to choose from, we recommend grouping units by `membershipBenefit.id` and displaying those units in a highlighted box.

Units with `"membershipBenefit": null` should go at the end as they are now, these are the regular units that weren't made available with the membership.

Include these units in the `unitItems` array as normal, ensuring you also include the `membership` object in the booking request.

When a membership unit benefit has limits, `unit.restrictions.maxQuantity` will be reduced to the lowest effective limit.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/memberships/bookings" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Returns bookings linked to the selected membership.

**Query Parameters**

The `membership` object is required on this endpoint. Include `membership[id]`, one lookup identifier (`membership[email]`, `membership[mobile]` or `membership[reference]`), and `membership[verification]`.

## Offers Benefits

Memberships also provide discounts on availability when using the `octo/offers` capability.

When this is used alongside `octo/offers`, a `membershipBenefit` field is added to the offer object:

`offer.membershipBenefit` uses the same fields as `unit.membershipBenefit` (`id`, `title`, `description`).

No additional action is required to select this offer. It is applied automatically, just like an entered `offerCode` or a public promotion. If `offer.membershipBenefit` is set, display `membershipBenefit.title/description` in place of `offer.title/description` wherever you show offer text.

## Booking / Order

Finally, when creating the booking or order (if you're using the `octo/cart` capability), include the membership object as in the steps above.

Membership-related request fields are included on the operations in this section.

This will associate the booking to the membership and automatically apply any benefits available.

Membership-related response fields are returned on the same operations.

When bookings are nested inside an order response, the membership summary is returned on the order object (`order.membership`) and omitted from each nested booking item.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `AvailabilityBatchRequest`

```json
{
  "// ...rest of availability batch request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `AvailabilityCalendarBatchRequest`

```json
{
  "// ...rest of availability calendar batch request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `AvailabilityCalendarRequest`

```json
{
  "// ...rest of availability calendar request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `AvailabilityRequest`

```json
{
  "// ...rest of availability request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "membership": {
    "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "title": "Annual Membership",
    "contact": {
      "firstName": "Jane",
      "lastName": "Doe",
      "emailAddress": "jane.doe@goldengatetours.com",
      "phoneNumber": "+12025550123",
      "country": "US"
    },
    "reference": "REF-2026-001",
    "resellerReference": "RES-MEM-10045",
    "supplierReference": "SUP-MEM-7782",
    "availabilityLocalDateStart": "2026-01-01",
    "availabilityLocalDateEnd": "2026-12-31"
  },
  "appendMembershipValidity": true
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  },
  "appendMembershipValidity": true
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "membership": {
    "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "title": "Annual Membership",
    "contact": {
      "firstName": "Jane",
      "lastName": "Doe",
      "emailAddress": "jane.doe@goldengatetours.com",
      "phoneNumber": "+12025550123",
      "country": "US"
    },
    "reference": "MEM-2026-001",
    "resellerReference": "RES-MEM-10045",
    "supplierReference": "SUP-MEM-7782",
    "availabilityLocalDateStart": "2026-01-01",
    "availabilityLocalDateEnd": "2026-12-31"
  }
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `Offer`

```json
{
  "// ...rest of offer object": "...",
  "membershipBenefit": {
    "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "title": "VIP Member Discount",
    "description": "Reduced pricing for active members."
  }
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "membership": {
    "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "title": "Annual Membership",
    "contact": {
      "firstName": "Jane",
      "lastName": "Doe",
      "emailAddress": "jane.doe@goldengatetours.com",
      "phoneNumber": "+12025550123",
      "country": "US"
    },
    "reference": "MEM-2026-001",
    "resellerReference": "RES-MEM-10045",
    "supplierReference": "SUP-MEM-7782",
    "availabilityLocalDateStart": "2026-01-01",
    "availabilityLocalDateEnd": "2026-12-31"
  }
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "membership": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "email": "jane.doe@goldengatetours.com",
    "verification": "123456"
  }
}
```

### `Product`

```json
{
  "// ...rest of product object": "...",
  "isMembership": true,
  "membershipAutoRenew": true
}
```

### `Unit`

```json
{
  "// ...rest of unit object": "...",
  "membershipBenefit": {
    "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
    "title": "VIP Member Discount",
    "description": "Reduced pricing for active members."
  },
  "isMembership": true
}
```


# Price Adjustments

Allows you to adjust the retail rate of a booking

To use this capability, add `octo/adjustments` to your `Octo-Capabilities` header.

This capability lets you adjust the retail rate of a booking. The adjustment amount can be positive (to increase the price) or negative (to decrease the price).

The adjustment is deducted from or added to your commission on the booking. You cannot adjust a booking below commission (`commission = retail - net`).

## Supported Endpoints

This capability extends booking write routes documented in [Bookings](/octo-core/bookings#endpoints) and, when `octo/cart` is enabled, order write routes documented in [Multi-Booking Cart](/capabilities/cart).

Affecting booking routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

When `octo/cart` is enabled, the same additions are supported on nested `bookings[]` payloads in order write routes.

The only addition to the booking object in the request is the `adjustments` array:

`adjustments` is an array, so you can send multiple adjustments.

## Request Fields

If request values are invalid, the API returns booking errors including `ADJUSTMENTS_INVALID_PER`, `ADJUSTMENTS_INVALID_NET_DISCOUNT`, and `ADJUSTMENTS_NET_DISCOUNT_NOT_ALLOWED`.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "adjustments": [
    {
      "per": "BOOKING",
      "amount": 220.0,
      "quantity": 2,
      "notes": "Vegetarian meal requested",
      "netDiscount": "NONE"
    }
  ]
}
```


# Webhooks

Configure webhook endpoints for order, booking, availability, and product updates

To use this capability, add `octo/webhooks` to your `Octo-Capabilities` header.

All paths below are shown under `/octo`.

This capability lets you configure outbound HTTP webhooks for:

* `order_update`
* `booking_update`
* `availability_update`
* `product_update`

## Webhook Object

All webhook CRUD endpoints return the same object shape.

`capabilities` come from the `Octo-Capabilities` header on create/update requests, not from request body fields. For `order_update`, `octo/cart` is always included automatically.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/webhooks" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Create a webhook.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/webhooks/{webhookId}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Update an existing webhook.

Same fields as Create Webhook, but all are optional.

`capabilities` are recalculated from the request `Octo-Capabilities` header every time you update.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/webhooks" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

List webhooks for the authenticated connection.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/webhooks/{webhookId}" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/webhooks" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Provide `url` as a query parameter or request body field.

## Outbound Delivery Payloads

When a webhook is delivered to your URL, the HTTP method is always `POST`.

### `webhook` Fields

`webhook` is the same `Webhook Object` shown above.

### `supplier` Fields

If additional capabilities are active on the webhook, `supplier` may include more fields added by those capabilities.

### `diff[]` Fields

`diff` is emitted for `order_update`, `booking_update`, and `product_update`.

### Event Object Serialization

The event object payloads use the same serializer methods as the corresponding API endpoints, with the webhook's stored capabilities activated first:

* `order` uses the same serialized shape as `GET /orders/:orderId`.
* `booking` uses the same serialized shape as `GET /bookings/:uuid`.
* `product` uses the same serialized shape as `GET /products/:productId`.
* `availability` uses one serialized item from `GET /availability`.

This means capability-specific fields (for example content/pricing/extras/questions fields) are included in webhook payloads the same way they appear in those endpoint responses.

When `octo/cardPayments` is active, webhook delivery serialization suppresses card payment session payload generation, so detailed `cardPayment` payloads are not emitted.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Webhook`

```json
{
  "// ...rest of webhook object": "...",
  "id": "webhook_booking_update",
  "event": "booking.updated",
  "url": "https://www.city-sightseeing.com",
  "capabilities": [
    "octo/pricing",
    "octo/offers"
  ],
  "useContactLanguage": true,
  "headers": {
    "X-Webhook-Secret": "whsec_123456abcdef"
  },
  "retryOnError": true
}
```

### `WebhookDeleteByUrlRequest`

```json
{
  "// ...rest of webhook delete by url request object": "...",
  "url": "https://hooks.example-partner.com/octo/webhook"
}
```

### `WebhookDiffOperation`

```json
{
  "// ...rest of webhook diff operation object": "...",
  "op": "add",
  "path": "path-example",
  "was": "was-example",
  "value": "value-example"
}
```

### `WebhookEventPayload`

```json
{
  "// ...rest of webhook event payload object": "...",
  "event": "booking.updated",
  "webhook": {
    "id": "webhook_booking_update",
    "event": "booking.updated",
    "url": "https://www.city-sightseeing.com"
  },
  "supplier": {
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "name": "City Sightseeing Group",
    "reference": "CITY_SIGHTSEEING_GROUP",
    "website": "https://www.city-sightseeing.com"
  },
  "order": {
    "orderId": "ord_20260514_9f3c21",
    "status": "ON_HOLD",
    "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7"
  },
  "booking": {
    "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "status": "ON_HOLD",
    "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2"
  },
  "product": {
    "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
    "internalName": "Walking Tour of Barcelona",
    "reference": "BRC-WALK",
    "tags": [
      "vip",
      "partner"
    ]
  },
  "availability": {
    "id": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
    "localDateTimeStart": "2026-03-01T09:00:00-08:00",
    "localDateTimeEnd": "2026-03-01T12:00:00-08:00",
    "allDay": false,
    "available": true,
    "status": "AVAILABLE",
    "statusMessage": "Limited availability for this departure.",
    "utcCutoffAt": "2026-05-14T13:00:00Z",
    "openingHours": [
      {
        "from": "09:00",
        "to": "17:00"
      }
    ]
  },
  "diff": [
    {
      "op": "add",
      "path": "path-example",
      "was": "was-example",
      "value": "value-example"
    }
  ]
}
```

### `WebhookRequest`

```json
{
  "// ...rest of webhook request object": "...",
  "event": "booking.updated",
  "url": "https://hooks.example-partner.com/octo/webhook"
}
```


# Waitlists

Create waitlist entries for unavailable dates

To use this capability, add `octo/waitlists` to your `Octo-Capabilities` header.

All waitlist paths below are under `/octo`.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/waitlists" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

At least one non-item unit quantity must resolve to a total waitlist size greater than `0` (entries resolved to `item_...` do not add to waitlist size).

### Response Fields

When personal information masking is enabled on the connection, the same `contact` fields are returned but personal values are `null`.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Waitlist`

```json
{
  "// ...rest of waitlist object": "...",
  "id": "f1a5d2e8-8d57-4f0b-9c3f-6a12d7a8bc90",
  "status": "ACTIVE",
  "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b",
  "productId": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
  "localDate": "2026-05-14",
  "units": [
    {
      "unitId": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
      "quantity": 2
    }
  ],
  "contact": {
    "fullName": "Jane Doe",
    "emailAddress": "jane.doe@goldengatetours.com"
  },
  "createdAt": "2026-05-14T10:00:00Z",
  "uuid": "89fe0192-ddcd-430a-b285-e1396a4725d2",
  "supplierReference": "SUP-BOOK-7782",
  "size": 2,
  "visibleContactFields": [
    "fullName",
    "emailAddress"
  ],
  "requiredContactFields": [
    "fullName",
    "emailAddress"
  ],
  "utcCreatedAt": "2026-05-14T13:00:00Z",
  "utcUpdatedAt": "2026-05-14T13:00:00Z"
}
```

### `WaitlistRequest`

```json
{
  "// ...rest of waitlist request object": "...",
  "optionId": "94cdd032-3d32-416d-b0a4-abf8b7495b8b"
}
```

### `WaitlistUnit`

```json
{
  "// ...rest of waitlist unit object": "...",
  "unitId": "unit_adult",
  "quantity": 2
}
```


# Identities

Link external customer identities to orders, bookings, and gifts

To use this capability, add `octo/identities` to your `Octo-Capabilities` header.

{% hint style="warning" %}
`octo/identities` is currently an internal capability (`internal: true`) in the API source.
{% endhint %}

All paths below are public `/octo` routes.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/identities" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/identities/{identityId}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/identities/{identityId}" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

`200 OK` with empty body.

## Attach Identity to Orders, Bookings, and Gifts

With this capability enabled, you can include `identityId` in any booking/order/gift payload handled by the create/update flows.

Order routes:

* `POST /orders`
* `PATCH /orders/{orderId}`
* `PATCH /orders/{orderId}/preview`
* `POST /orders/{orderId}/confirm`

Booking routes:

* `POST /bookings`
* `PATCH /bookings/{uuid}`
* `POST /bookings/{uuid}/confirm`

Gift routes:

* `POST /gifts`
* `PATCH /gifts/{uuid}`
* `PATCH /gifts/{uuid}/preview`
* `POST /gifts/{uuid}/confirm`

Base schemas: [Bookings](/octo-core/bookings#endpoints), [Multi-Booking Cart](/capabilities/cart), and [Gift Vouchers](/capabilities/gift-vouchers#endpoints).

When creating or updating an order with nested `bookings` and `gifts` arrays, each nested item can also include its own `identityId`.

## Check-in Lookup With Identity

When used with `octo/checkin`, check-in lookup can match bookings by identity.

This capability extends `POST /checkin/lookup` from [Online Check-in](/capabilities/online-check-in#lookup) with an identity filter.

### Request Body Additions

If `identityId` is not provided, check-in lookup behavior falls back to the standard `octo/checkin` lookup inputs.

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `Booking`

```json
{
  "// ...rest of booking object": "...",
  "identityId": "identity_customer_001",
  "identity": {
    "id": "89fe0192-ddcd-430a-b285-e1396a4725d2",
    "key": "loyalty_number"
  }
}
```

### `BookingWriteRequest`

```json
{
  "// ...rest of booking write request object": "...",
  "identityId": "identity_customer_001"
}
```

### `Gift`

```json
{
  "// ...rest of gift object": "...",
  "identityId": "identity_customer_001",
  "identity": {
    "id": "3d6f0a3a-59d4-4b16-a0c5-11d2d8a4e6b7",
    "key": "loyalty_number"
  }
}
```

### `GiftCreateRequest`

```json
{
  "// ...rest of gift create request object": "...",
  "identityId": "identity_customer_001"
}
```

### `Order`

```json
{
  "// ...rest of order object": "...",
  "identityId": "identity_customer_001",
  "identity": {
    "id": "e7cc8bb4-8d1c-4848-8824-5dbedb718681",
    "key": "loyalty_number"
  }
}
```

### `OrderCreateRequest`

```json
{
  "// ...rest of order create request object": "...",
  "identityId": "identity_customer_001"
}
```

### `OrderUpdateRequest`

```json
{
  "// ...rest of order update request object": "...",
  "identityId": "identity_customer_001"
}
```


# Campaigns

Retrieve supplier campaigns

To use this capability, add `octo/campaigns` to your `Octo-Capabilities` header.

This capability adds the campaigns catalog endpoint.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/campaigns" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `NotifyRequest`

```json
{
  "// ...rest of notify request object": "...",
  "campaignId": "campaign_spring_2026"
}
```


# Notifications

Manage notification subscriptions for booking, availability, and product updates

To use this capability, add `octo/notifications` to your `Octo-Capabilities` header.

All paths below are shown under `/octo`.

## Supported Notification Types

* `BOOKING_UPDATE`
* `AVAILABILITY_UPDATE`
* `PRODUCT_UPDATE`

`notificationTypes` are case-insensitive in requests and returned as uppercase values in responses.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/notifications/subscriptions" method="post" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/notifications/subscriptions/{subscriptionId}" method="patch" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/notifications/subscriptions/{subscriptionId}" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/notifications/subscriptions" method="get" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Returns a paginated array of `Subscription Object` items.

{% openapi src="/files/9aBZzqykFPaTU7bfbNrr" path="/notifications/subscriptions/{subscriptionId}" method="delete" %}
[openapi.yaml](https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fgit-blob-fa2d8cb1d7297d352c2639e6c4c6a990f2add6d7%2Fopenapi.yaml?alt=media)
{% endopenapi %}

Deletes a subscription.

## Notification Payload Sent To Your URL

`data` fields by notification type:

* `BOOKING_UPDATE`: `uuid`
* `AVAILABILITY_UPDATE`: `productId`, `optionId`, `availabilityIds`
* `PRODUCT_UPDATE`: `productId`

## Schema Additions (JSON)

These are additive fragments showing only fields introduced by this capability.

### `NotificationSubscription`

```json
{
  "// ...rest of notification subscription object": "...",
  "subscriptionId": "sub_booking_update_01",
  "url": "https://www.city-sightseeing.com",
  "notificationTypes": [
    "STANDARD"
  ],
  "headers": {
    "X-Webhook-Secret": "whsec_123456abcdef"
  },
  "retryOnError": true
}
```

### `NotificationSubscriptionRequest`

```json
{
  "// ...rest of notification subscription request object": "...",
  "notificationTypes": [
    "BOOKING_UPDATE"
  ],
  "url": "https://hooks.example-partner.com/octo/webhook"
}
```


# Ventrata Clients

Developing this integration enables resellers to establish API connectivity with suppliers using Ventrata as their ticketing platform. This page lists attraction, tour, and activity operators on Ventrata that you can connect to through the OCTO API.

{% hint style="info" %}
Resellers need commercial agreements with each supplier. Ventrata acts only as a technology partner to suppliers and resellers, helping facilitate API connectivity, and does not participate in commercial agreements between the parties.
{% endhint %}

You can access the [full client list](#full-client-list) below and review the [featured clients](#featured-clients) that resellers most often ask about.

## Full Client List

Access our complete and up-to-date client list:

* [Ventrata full client list (Google Sheets)](https://docs.google.com/spreadsheets/d/1wosrJ9nbr2P8K9SfiLif4Z9pVdBjc9SgDbrYkYdaxAk/edit#gid=1690624965)

## Featured Clients

Ventrata's ticketing system is used by operators across the industry:

<table data-view="cards"><thead><tr><th>Client</th><th>Description</th><th data-hidden data-card-target data-type="content-ref">Website</th><th data-hidden data-card-cover data-type="files">Cover image</th></tr></thead><tbody><tr><td><strong>Big Bus Tours</strong></td><td>A major operator of open-top hop-on hop-off bus tours, operating in 27+ cities.</td><td><a href="https://www.bigbustours.com/">https://www.bigbustours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FaB9yaF3OAmYr30AwwhTO%2FBig-Bus-Tours_New-York_desktop_3.jpg?alt=media&amp;token=db0b19a6-653e-48da-b40d-69a4a1f795f6">Big-Bus-Tours_New-York_desktop_3.jpg</a></td></tr><tr><td><strong>Empire State Building</strong></td><td>Observatory experience at an iconic U.S. landmark; ranked a top U.S. attraction in 2022 and 2023 (Tripadvisor).</td><td><a href="https://www.esbnyc.com/">https://www.esbnyc.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FYX9nbEaaHmrYQQbcM7fJ%2Fesb.jpeg?alt=media&amp;token=ec55edb8-308e-48c8-b082-a1a7090e0549">esb.jpeg</a></td></tr><tr><td><strong>Crown Tours</strong></td><td>One of the leading operators of curated tours and experiences in Vatican and Rome.</td><td><a href="https://crowntours.com/">https://crowntours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FGCYOlLqpNhfxaZDz2K3t%2Fcrown%20tours.jpeg?alt=media&amp;token=398f3180-b89d-433f-9a67-e562fa83b448">crown tours.jpeg</a></td></tr><tr><td><strong>Golden Tours</strong></td><td>UK operator specializing in day trips, hop-on hop-off tours, guided tours, and attractions.</td><td><a href="https://www.goldentours.com/">https://www.goldentours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fl2nflb054KHTGRBCY4aw%2FGolden%20Tours.jpeg?alt=media&amp;token=ba12c635-f750-4420-adad-cd717ebeb595">Golden Tours.jpeg</a></td></tr><tr><td><strong>Sightseeing Pass</strong></td><td>One of the leading attraction pass providers in New York City and 16+ cities around the world.</td><td><a href="https://www.sightseeingpass.com/">https://www.sightseeingpass.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FcE2qnanoHNKKizHM8f1f%2Fsightseeingpass__large.jpg?alt=media&amp;token=e7c2f33f-55db-4770-b9b7-2f526d5b2d20">sightseeingpass__large.jpg</a></td></tr><tr><td><strong>City Sightseeing New York</strong></td><td>New York Sightseeing, CitySights NY, Twin America.</td><td><a href="https://www.citysightseeingnewyork.com/">https://www.citysightseeingnewyork.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FLiaAesfKJvYC9yV53JUJ%2Fcsny.jpeg?alt=media&amp;token=0d4a82de-3398-4a65-b86c-5e41deaa4a4f">csny.jpeg</a></td></tr><tr><td><strong>Historic Tours of America</strong></td><td>Leading operator of historically oriented tours and attractions across the United States, including famous Old Town Trolley.</td><td><a href="https://www.historictours.com/">https://www.historictours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FK3UtkPJY1yhiNvhrPD6X%2FHTA.jpeg?alt=media&amp;token=3373b90a-5d96-459b-8340-f5d30d761910">HTA.jpeg</a></td></tr><tr><td><strong>360 CHICAGO</strong></td><td>Observation deck in Chicago featuring a tilting glass experience around 1,000 ft above the city.</td><td><a href="https://360chicago.com/">https://360chicago.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fig6YeQKE4TjGky91zu0f%2F360.jpeg?alt=media&amp;token=918b9b2f-a5c8-46f2-ab6c-f88fb65efb3a">360.jpeg</a></td></tr><tr><td><strong>Paris Montparnasse Tower</strong></td><td>Open-air rooftop on one of Paris's tallest buildings with views of the Eiffel Tower.</td><td><a href="https://www.tourmontparnasse56.com/en/">https://www.tourmontparnasse56.com/en/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FF8TCIoByfQuT3TF9uNwI%2Fmontparnasse.jpeg?alt=media&amp;token=94f2424e-f2f8-4bf1-80b0-92e9cdf7ac34">montparnasse.jpeg</a></td></tr><tr><td><strong>Euromast Rotterdam</strong></td><td>Observation tower with 360º panoramic views over Rotterdam and the largest harbor in Europe.</td><td><a href="https://euromast.nl/en/">https://euromast.nl/en/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FvqDgF4P6AHNf6RdteeeD%2F145.jpg?alt=media&amp;token=6294bb27-aaf1-4e45-94ee-994bc0669460">145.jpg</a></td></tr><tr><td><strong>Berlin TV Tower (NEW)</strong></td><td>Stunning 360-degree Berlin views from observation deck and a revolving restaurant.</td><td><a href="https://tv-turm.de/">https://tv-turm.de/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FSBghmEXLD8IbXGFroiuT%2Fberlin-tv-turm.webp?alt=media&amp;token=8af564ef-b7c6-45e1-a34c-488aa7bfe2f6">berlin-tv-turm.webp</a></td></tr><tr><td><strong>Zalmhaven Rotterdam</strong></td><td>Unique experience on the top floors of the tallest tower in the Benelux.</td><td><a href="https://www.magnicity.com/project/zalmhaven/">https://www.magnicity.com/project/zalmhaven/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F1NpuE3rcnzgfl8g09xyX%2FZalmhaven.jpeg?alt=media&amp;token=c1db5b5c-7f50-4aea-86f3-1371dbe9de9f">Zalmhaven.jpeg</a></td></tr><tr><td><strong>Varso Tower (COMING 2025)</strong></td><td>Planned Warsaw observation deck on one of the EU's tallest buildings.</td><td><a href="https://www.magnicity.com/project/magnicity-warsaw/">https://www.magnicity.com/project/magnicity-warsaw/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F9YBzU2cw2CBqYE3SOusl%2Fvarso.jpeg?alt=media&amp;token=3a85e404-5074-4c38-b55b-504b0c324155">varso.jpeg</a></td></tr><tr><td><strong>FlyOver Las Vegas (NEW)</strong></td><td>An immersive flying journey that transports you over iconic global destinations.</td><td><a href="https://www.flyoverlasvegas.com/">https://www.flyoverlasvegas.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FJUQxShGFmttEvsJcELaP%2Ffolv.jpg?alt=media&amp;token=d78397a4-3523-43ef-b5b8-26fd9276d810">folv.jpg</a></td></tr><tr><td><strong>Yankee Freedom Dry Tortugas Ferry</strong></td><td>Ferry trips to Dry Tortugas National Park from Key West.</td><td><a href="https://www.drytortugas.com/">https://www.drytortugas.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F2ByNatohV8qdujx4woqd%2Fyankeefreedom.jpeg?alt=media&amp;token=a4e99e08-b739-4b17-84fe-3a4119409a85">yankeefreedom.jpeg</a></td></tr><tr><td><strong>Boston Tea Party Ships &#x26; Museum</strong></td><td>Interactive experience with reenactments, replica ships, and historic artifacts.</td><td><a href="https://www.bostonteapartyship.com/">https://www.bostonteapartyship.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F610IGojuecBxfUCrc3qF%2Fteaparty.jpeg?alt=media&amp;token=ad16068d-16ae-4023-87ea-63cb6edadc74">teaparty.jpeg</a></td></tr><tr><td><strong>Tower Bridge</strong></td><td>London landmark experience featuring engine rooms and a high-level glass walkway.</td><td><a href="https://www.towerbridge.org.uk/">https://www.towerbridge.org.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FaWfGeTOed5r0aQ4vmI3b%2FTower%20Bridge.jpeg?alt=media&amp;token=94cc38b0-5464-4be2-b5b6-2df46369c5f2">Tower Bridge.jpeg</a></td></tr><tr><td><strong>Vedettes De Paris</strong></td><td>Famous Seine River cruises, including guided tours, family cruises, and evening aperitif cruises.</td><td><a href="https://www.vedettesdeparis.fr/">https://www.vedettesdeparis.fr/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FtYp5ybxEifvgamw7iAWb%2Fvedettes2.jpeg?alt=media&amp;token=b9b6a391-bd75-4e99-a70c-e3cc152efc6f">vedettes2.jpeg</a></td></tr><tr><td><strong>Uber Boat by Thames Clippers</strong></td><td>London's river bus services with the fleet of 18 luxury high speed catamarans.</td><td><a href="https://www.thamesclippers.com/">https://www.thamesclippers.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FAyP0HGvHRuKhDvpG8bWo%2Fuber%20boat.jpeg?alt=media&amp;token=aa53312c-b15c-4a88-87fb-f6c92ed528c4">uber boat.jpeg</a></td></tr><tr><td><strong>Tootbus</strong></td><td>Operator of eco-friendly hop-on hop-off tours in six major European cities (formerly Open Tour / Original Tour).</td><td><a href="https://www.tootbus.com/en">https://www.tootbus.com/en</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FDwGTrjredz6qwJQWglzB%2FCleanShot%202023-06-07%20at%2011.17.44%402x.png?alt=media&amp;token=ddc5f8a4-1d29-455e-a5c0-17f06cb737df">CleanShot 2023-06-07 at 11.17.44@2x.png</a></td></tr><tr><td><strong>Jasper SkyTram</strong></td><td>Scenic aerial tramway in Jasper National Park with breathtaking views of the Canadian Rockies.</td><td><a href="https://www.jasperskytram.com/">https://www.jasperskytram.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FASCLu18jZ66U3jxfJ3jo%2Fjst.jpeg?alt=media&amp;token=b6ea52ce-868a-4958-a968-9e2b3d4774ff">jst.jpeg</a></td></tr><tr><td><strong>Gray Line Westcoast Sightseeing</strong></td><td>HoHo, guided tours and attractions in Vancouver, Victoria, Whistler. Part of CTCE.</td><td><a href="https://westcoastsightseeing.com/">https://westcoastsightseeing.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FiblXIYSLSSRE9ONiix2W%2Fglwcs.jpeg?alt=media&amp;token=20f93d56-a152-4c7b-ab91-a729110c20c3">glwcs.jpeg</a></td></tr><tr><td><strong>Gray Line Niagara Falls/Buffalo</strong></td><td>Tours and attractions at Niagara Falls, including boat rides and cross-border experiences. CTCE.</td><td><a href="https://graylineniagarafalls.com/">https://graylineniagarafalls.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FCfYc42v4xyobWA9ELg4X%2FGL%20Niagara.png?alt=media&amp;token=c1aeaaa2-dec0-4e36-b054-eb8139a6b000">GL Niagara.png</a></td></tr><tr><td><strong>Gray Line Seattle / City Sightseeing Seattle</strong></td><td>Hop-On Hop-Off &#x26; guided city tours in Seattle. CTCE</td><td><a href="https://graylineseattle.com/">https://graylineseattle.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FuFed8FDPoz1r29rpAuPI%2Fcssea.jpeg?alt=media&amp;token=7526ec73-1c8b-4af2-acaa-2205d91c1bb8">cssea.jpeg</a></td></tr><tr><td><strong>Up at The O2 (NEW)</strong></td><td>Guided climb across the world-famous roof of The O2 with London views.</td><td><a href="https://www.upattheo2.co.uk/">https://www.upattheo2.co.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FQJavKlkqbQtuqv1Nm5fr%2Fo2.jpg?alt=media&amp;token=848a4dcd-7c55-4d4e-912f-1498137d52e8">o2.jpg</a></td></tr><tr><td><strong>Moco Museum (NEW)</strong></td><td>An independent museum in Amsterdam, Barcelona, and London, exhibiting modern and contemporary art.</td><td><a href="https://mocomuseum.com/">https://mocomuseum.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fs58ZGiM0ShVyWDiBggN4%2Fmoco.webp?alt=media&amp;token=3e89607a-a25c-489a-9628-594987ef4201">moco.webp</a></td></tr><tr><td><strong>Dubai Balloon At Atlantis</strong></td><td>One-of-a-kind 360-degree aerial observatory and one of the highest viewing points on The Palm.</td><td><a href="https://thedubaiballoon.com/">https://thedubaiballoon.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FNhmwzIk36ZSuC0RFAvXL%2FThe-Dubai-Balloon-At-Atlantis-1024x768.jpg?alt=media&amp;token=89ac1187-016d-41f1-a102-c9334d4d9464">The-Dubai-Balloon-At-Atlantis-1024x768.jpg</a></td></tr><tr><td><strong>Boston Duck Tours</strong></td><td>Boston's original and world-famous tours aboard WWII style amphibious vehicles.</td><td><a href="https://bostonducktours.com/">https://bostonducktours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FxkPUKhSlyKTQTVdjhldU%2FBoston%20Duck%20Tours.jpeg?alt=media&amp;token=d72cdd27-1a03-401b-a7d0-3da6d03acfb7">Boston Duck Tours.jpeg</a></td></tr><tr><td><strong>Yellow Bus Tours</strong></td><td>The leading open-top bus tour operator in Portugal, with presence in 7 most popular cities.</td><td><a href="https://www.yellowbustours.com/en">https://www.yellowbustours.com/en</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FgUYczVnv8trIDKl6yHcL%2FYellow%20Bus%20Tours.jpeg?alt=media&amp;token=08f184bc-3412-4712-a9e8-d5e14720180b">Yellow Bus Tours.jpeg</a></td></tr><tr><td><strong>Key Tours</strong></td><td>Tours, excursions, and attraction tickets across popular destinations in Greece.</td><td><a href="https://keytours.gr/">https://keytours.gr/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fz05fLHjdwToxF5t1AnTk%2Fkey%20tours.jpeg?alt=media&amp;token=18d962c4-a756-49be-b7d1-90abc797103b">key tours.jpeg</a></td></tr><tr><td><strong>Discover Banff Tours</strong></td><td>Interpretive sightseeing tours in Banff National Park, including ice walks, sleigh rides &#x26; wildlife tours.</td><td><a href="https://www.banfftours.com/">https://www.banfftours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FtUVySlL1RVpFnOM7r3BI%2FDiscover%20Banff.jpeg?alt=media&amp;token=fd5145d3-8916-48b6-8d56-0d6f71dba4d1">Discover Banff.jpeg</a></td></tr><tr><td><strong>Landsea Tours &#x26; Adventures</strong></td><td>Small group sightseeing tours in Vancouver, Whistler, and Victoria.</td><td><a href="https://vancouvertours.com/">https://vancouvertours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fx0uuyRx2vyKaAEWu4Ya9%2Flandsea.jpeg?alt=media&amp;token=52dd74af-f981-4b39-8c69-62a59d30482e">landsea.jpeg</a></td></tr><tr><td><strong>Old South Carriage Company</strong></td><td>Historic and haunted carriage tours in Charleston.</td><td><a href="https://oldsouthcarriage.com/">https://oldsouthcarriage.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FI046932idZv7mcfwiGPz%2Foldsouth.jpeg?alt=media&amp;token=b5e371bb-4953-4de0-b1cf-dc11a55c0b95">oldsouth.jpeg</a></td></tr><tr><td><strong>Airboat Adventures</strong></td><td>Swamp tours near New Orleans, featuring small and large airboats as well as pontoon boats.</td><td><a href="https://airboatadventures.com/">https://airboatadventures.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F47txPKivvMCDpl8b14v5%2Fairboat2.jpeg?alt=media&amp;token=78d40075-9c7e-4455-ace5-af6ed856c280">airboat2.jpeg</a></td></tr><tr><td><strong>Gray Line Operators</strong></td><td>Select GL operators: NYC, Seattle, London, Vancouver, Niagara Falls / Buffalo, and more.</td><td><a href="https://www.grayline.com/">https://www.grayline.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FmlpiEPslq8wlYzPdciYI%2FC2C.jpeg?alt=media&amp;token=17d1d652-72f9-4daf-9a1f-612b2b76f50e">C2C.jpeg</a></td></tr><tr><td><strong>City Sightseeing Operators</strong></td><td>*Selected CS operators: NYC, SF, San Antonio, Orlando, Prague, Athens, Galway, South Africa, Bournemouth</td><td><a href="https://city-sightseeing.com/">https://city-sightseeing.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FHB8SpaFcSeOD2KipDO8l%2F145.jpg?alt=media&amp;token=2c5f74d4-b18a-43ac-8a93-43e24dfec551">145.jpg</a></td></tr><tr><td><strong>Fat Tire Tours</strong></td><td>The largest city bicycle tour operation in the world, offering guided tours in English, rentals and more.</td><td><a href="https://www.fattiretours.com/">https://www.fattiretours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FBMyUsXZhDnFWHATYa61T%2FFTT.jpeg?alt=media&amp;token=56b85e96-31fa-4d56-8935-75ba83f067b3">FTT.jpeg</a></td></tr><tr><td><strong>Dig This Vegas</strong></td><td>A giant sandbox for grown-ups, this venue lets people operate bulldozers &#x26; excavators for fun.</td><td><a href="https://digthisvegas.com/">https://digthisvegas.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FFfuCs4cpKRTuEG11BbOX%2Fdig%20this.jpeg?alt=media&amp;token=6b64820b-25a6-4581-bf33-8e476f4198dc">dig this.jpeg</a></td></tr><tr><td><strong>Paris By Mouth</strong></td><td>Top-rated food tours in Paris, including cheese and wine tastings and visits to local markets.</td><td><a href="https://parisbymouth.com/">https://parisbymouth.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FnSeWxtdmui8FijiPwOZn%2Fparisbymouth.png?alt=media&amp;token=5d379451-d4be-40a7-9428-fcaa44ce3c0f">parisbymouth.png</a></td></tr><tr><td><strong>Balloon Adventures Dubai</strong></td><td>Longest-operating hot air balloon company in Dubai. Leading Operator by the World Travel Awards.</td><td><a href="https://www.balloon-adventures.com/">https://www.balloon-adventures.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FtBFHrF2b34ahvn4vq69K%2FBaloon%20Adventures.jpeg?alt=media&amp;token=b6f6b135-3a6c-413d-a052-b887414eccd8">Baloon Adventures.jpeg</a></td></tr><tr><td><strong>Hero Balloon Flights Saudi</strong></td><td>AlUla’s first commercial Hot Air Balloon Operator.</td><td><a href="https://sa.heroballoonflights.com/">https://sa.heroballoonflights.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FJIwsAdXACX8nagS1fGm2%2FHero-Balloon.jpeg?alt=media&amp;token=14a1a275-91a8-42c8-a50c-eda91a977fbb">Hero-Balloon.jpeg</a></td></tr><tr><td><strong>Platinum Heritage</strong></td><td>Middle East's Leading Desert Safari Company for six years in a row by World Travel Award.</td><td><a href="https://www.platinum-heritage.com/">https://www.platinum-heritage.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fe2fIdzqf7MwmrJpFkn7u%2Fplatinum%20heritage.jpeg?alt=media&amp;token=e637cf99-316c-4694-9b80-df3552474289">platinum heritage.jpeg</a></td></tr><tr><td><strong>Intrepid Urban Adventures</strong></td><td>170+ day tours and city tours worldwide, unique and immersive local experiences with knowledgeable guides.</td><td><a href="https://www.urbanadventures.com/">https://www.urbanadventures.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F9FI9UE2KucaTqIds1Gbc%2FUA-Food-tours.jpg?alt=media&amp;token=2b42cf2d-6464-4306-a441-70613cad2f7b">UA-Food-tours.jpg</a></td></tr><tr><td><strong>ExperienceFirst</strong></td><td>80+ immersive walking tours across 12 iconic destinations.</td><td><a href="https://www.exp1.com/">https://www.exp1.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FfdxoJZrWJtnBgat3bFOr%2Fexp1.jpeg?alt=media&amp;token=81386c5b-30c2-4960-a792-8df6e80db0d0">exp1.jpeg</a></td></tr><tr><td><strong>Paradox Museums*</strong></td><td>*Select locations: Oslo, Stockholm, Barcelona, Limassol, Paris, Berlin, etc.</td><td><a href="https://www.paradoxmuseum.com/">https://www.paradoxmuseum.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FtED6Kop2ra6xeaBsvX8K%2Fparadox.jpeg?alt=media&amp;token=c487ba4f-3d06-4bf5-ac46-f5328181f7e7">paradox.jpeg</a></td></tr><tr><td><strong>Museum of Illusions*</strong></td><td>*Select locations: Athens, Madrid, Thessaloniki, New Delhi, Istanbul (Istikal)</td><td><a href="https://www.museumofillusions.com/">https://www.museumofillusions.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FqrZ9et8gEstGrU05bBQ8%2Fmoi%20madrid.jpeg?alt=media&amp;token=39dd2495-6263-435b-b31b-4acbc224cf17">moi madrid.jpeg</a></td></tr><tr><td><strong>EPIC Museum</strong></td><td>Museum in Dublin with interactive experience exploring the history of Irish emigration its impact.</td><td><a href="https://epicchq.com/">https://epicchq.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FJsl6d86feegx1SvPYZhI%2FEPIC%20Museum.jpeg?alt=media&amp;token=3a537797-8f00-4ad4-901b-69e30d3df5d9">EPIC Museum.jpeg</a></td></tr><tr><td><strong>Jeanie Johnston</strong></td><td>Guided tours of a replica 19th-century famine ship in Dublin.</td><td><a href="https://jeaniejohnston.ie/">https://jeaniejohnston.ie/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FPeWPsXQ5mm14ARy1tdfD%2Fjj.jpeg?alt=media&amp;token=bcf18732-bf34-4cf7-80f4-08f49545e52e">jj.jpeg</a></td></tr><tr><td><strong>AVA Colorado Rafting</strong></td><td>Outdoor adventures in Colorado, including rafting, ziplining, rock climbing &#x26; more.</td><td><a href="https://www.coloradorafting.net/">https://www.coloradorafting.net/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fetj1BIXmdc3DWhRSwVEU%2Fava2.webp?alt=media&amp;token=9058aaa4-87b2-4775-b1da-ab09f110bb53">ava2.webp</a></td></tr><tr><td><strong>Starline Tours</strong></td><td>Famous LA Original Celebrity Homes Tour, hop-on hop-off, night tours, private city tours, and more.</td><td><a href="https://www.starlinetours.com/">https://www.starlinetours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FrNByl25PYGLlbi92S3xM%2F2Starline%20Tours.jpeg?alt=media&amp;token=2c889b25-18e3-454c-ad83-911ed1239597">2Starline Tours.jpeg</a></td></tr><tr><td><strong>The Ride</strong></td><td>75-minute theatrical bus experience in NYC as you travel through the city.</td><td><a href="https://experiencetheride.com/">https://experiencetheride.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FOuoZ83YI9NgVknbg6lcT%2Fride.jpeg?alt=media&amp;token=60d50417-5205-4077-9509-d952e6970626">ride.jpeg</a></td></tr><tr><td><strong>SKY Helicopters</strong></td><td>Helicopter tours and experiences in Vancouver, including scenic flights and backcountry adventures.</td><td><a href="https://skyhelicopters.ca/">https://skyhelicopters.ca/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FILGq0USG8NTEDK78mYgj%2Fsky.jpeg?alt=media&amp;token=99c911d9-78f8-4039-bdb2-f3dc332dec4f">sky.jpeg</a></td></tr><tr><td><strong>Paramount Studio Tours</strong></td><td>Guided tours of the historic Paramount Pictures studio Hollywood.</td><td><a href="https://www.paramountstudiotour.com/">https://www.paramountstudiotour.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FOeBmiGEB114oc2tVemiT%2Fparamount.webp?alt=media&amp;token=a6ed6f81-dd6d-4801-bb0c-a7cfe6067301">paramount.webp</a></td></tr><tr><td><strong>Lally Tours</strong></td><td>Guided tours from Galway, including trips to the Cliffs of Moher, Connemara, and the Aran Islands.</td><td><a href="https://www.lallytours.com/">https://www.lallytours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FYdTL60kclBt6PimQFiFC%2Flally2.jpeg?alt=media&amp;token=dcdf4d7a-7224-4a0f-9277-364df5383726">lally2.jpeg</a></td></tr><tr><td><strong>Discover Dorset Tours</strong></td><td>Guided tours showcasing the scenic beauty of Dorset with knowledgeable local guides.</td><td><a href="https://www.discoverdorset.co.uk/">https://www.discoverdorset.co.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FXz2QFb225d7jmjnQJclV%2Fdorset.jpeg?alt=media&amp;token=fd459b3c-9d7c-4e95-abe3-93f28d1740c4">dorset.jpeg</a></td></tr><tr><td><strong>Thames RIB Experience</strong></td><td>High-speed speedboat tours on the River Thames in London. Thames Beast.</td><td><a href="https://thamesribexperience.com/">https://thamesribexperience.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FfK9KfgpcifUb2sllYhhF%2Frib.jpeg?alt=media&amp;token=3e0afcb8-dd13-4abd-9c06-5224c6251033">rib.jpeg</a></td></tr><tr><td><strong>Tugatrips</strong></td><td>Popular guided tours in Portugal, focusing on Lisbon, Sintra, Cascais.</td><td><a href="https://tugatrips.com/">https://tugatrips.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FEnBtSEvVoErV5zV6Fj4E%2Ftigatrips.jpeg?alt=media&amp;token=1866b9a5-1816-4b19-b4eb-a4389e65e25c">tigatrips.jpeg</a></td></tr><tr><td><strong>Pilsner Urquell Experience</strong></td><td>Interactive experience showcasing the history and brewing process of the world's first golden beer.</td><td><a href="https://www.pilsnerexperience.com/">https://www.pilsnerexperience.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FpswBRFviILzit4QemUJi%2Fpilsner.jpeg?alt=media&amp;token=3bf86c20-d54c-4427-920b-a2457f846276">pilsner.jpeg</a></td></tr><tr><td><strong>The EDGE Ziplines &#x26; Adventures</strong></td><td>Ziplining, a sky trek course, and a ninja course in Castle Rock, CO.</td><td><a href="https://theedgezip.com/">https://theedgezip.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F6Bml3Zd43ywECdYXimtw%2Ftheedge.jpeg?alt=media&amp;token=e230b0d6-45e0-4695-85bd-1250adcb79a1">theedge.jpeg</a></td></tr><tr><td><strong>City Sightseeing South Africa</strong></td><td>Hop-on hop-off bus tours in Cape Town and Johannesburg.</td><td><a href="https://www.citysightseeing.co.za/">https://www.citysightseeing.co.za/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FIfTPlBPltGoi3JLw2hcL%2Fcsssa.jpeg?alt=media&amp;token=6cbc2a6d-7cba-482a-9842-ba1ecf1702bb">csssa.jpeg</a></td></tr><tr><td><strong>Mountain Goat Tours</strong></td><td>Small group guided tours in Northern England, including the Lake District, North Wales, and Yorkshire.</td><td><a href="https://www.mountain-goat.com/">https://www.mountain-goat.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F9AwN6Oqxp6hp0D2mzIYC%2Fgoat.jpeg?alt=media&amp;token=15077dda-90ef-49fc-9cea-a1b3fc35d8ac">goat.jpeg</a></td></tr><tr><td><strong>Le Centre d'Activités Mont-Tremblant</strong></td><td>75+ outdoor activities in Mont-Tremblant, including rafting, canoeing, kayaking, ziplining, and more.</td><td><a href="https://www.tremblantactivities.com/">https://www.tremblantactivities.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FYVe2ZUGHsjEfi52vKk4W%2Ftremblant.webp?alt=media&amp;token=5015a9e4-2aed-4109-b718-1c006c72ab0a">tremblant.webp</a></td></tr><tr><td><strong>CruiseRI</strong></td><td>Coastal Queen Cruises, Jamestown Newport Ferry. Scenic cruises, hop-on hop-off ferry &#x26; more.</td><td><a href="https://www.cruiseri.com/">https://www.cruiseri.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FAbSgaP1B2BQh48LmkCJL%2Fcruiseri.jpeg?alt=media&amp;token=9649734f-9a45-4f9c-a55c-0073b773e75c">cruiseri.jpeg</a></td></tr><tr><td><strong>FRS Portugal</strong></td><td>Panoramic boat trips on the Tagus River in Lisbon, providing scenic views of famous landmarks.</td><td><a href="https://www.frs-portugal.pt/">https://www.frs-portugal.pt/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F4F1prXxkoKAJc0QvAMjY%2Fcsm_frs-portugal-ms-hanseblick_72a7870156.jpg?alt=media&amp;token=d4844629-2754-4e27-9a2b-81d112df0722">csm_frs-portugal-ms-hanseblick_72a7870156.jpg</a></td></tr><tr><td><strong>Skyline Sightseeing</strong></td><td>SF hop-on hop-off bus tours, Alcatraz excursions, wine country tours, and city tours.</td><td><a href="https://sightseeingworld.com/en">https://sightseeingworld.com/en</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FgvWgSz0zrJ5Km9K3LTft%2F2023-05-25.jpg?alt=media&amp;token=6a81ace2-3065-4f83-90f5-06ffad122dc1">2023-05-25.jpg</a></td></tr><tr><td><strong>Rémy Martin</strong></td><td>Distillery tours at Rémy Martin historic estate in Cognac, France.</td><td><a href="https://www.remymartin.com/">https://www.remymartin.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F63WI0bOcEPFhTemYp88W%2Fremy.jpeg?alt=media&amp;token=861c9151-7111-4ff0-9724-6f1570c2f5e9">remy.jpeg</a></td></tr><tr><td><strong>Cointreau</strong></td><td>Guided tours and museum at Carré Cointreau distillery in Saint-Barthélemy-d'Anjou.</td><td><a href="https://www.cointreau.com/">https://www.cointreau.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FW0kYwfzzwFhNlaSp68PU%2Fcointreau.jpeg?alt=media&amp;token=b6a32931-5464-4928-826c-d3012d88512c">cointreau.jpeg</a></td></tr><tr><td><strong>Manchester River Cruises</strong></td><td>Tours and events on the Manchester's waterways, including historical canal tours &#x26; live music cruises.</td><td><a href="https://manchesterrivercruises.com/">https://manchesterrivercruises.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fhzox3BXy3DVu7gYX9xWZ%2Fman.jpeg?alt=media&amp;token=d3558780-8ff6-415f-9761-33044f4b8a4f">man.jpeg</a></td></tr><tr><td><strong>ItaliaTours</strong></td><td>Guided tours across Italy, including day trips, skip-the-line access and unique experiences.</td><td><a href="https://italiatours.com/">https://italiatours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FyAJ0M8WktTpexaYisOrR%2Fitaliatours.jpeg?alt=media&amp;token=f1946cc0-43ed-4f7a-b3fe-791f1e6a6e6a">italiatours.jpeg</a></td></tr><tr><td><strong>Perth Explorer</strong></td><td>Hop-on hop-off bus tours in Perth, featuring stops at key attractions.</td><td><a href="https://www.perthexplorer.com.au/">https://www.perthexplorer.com.au/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FzaTtIVWHnWEvnrN9ZvNM%2Fperth.jpeg?alt=media&amp;token=97a832ae-507b-4b93-bfbd-ca82e6ff6e9c">perth.jpeg</a></td></tr><tr><td><strong>The Great Canadian Trolley Company</strong></td><td>Hop-on hop-off sightseeing tours in Vancouver on classic trolley buses.</td><td><a href="https://greatcanadiantrolley.com/">https://greatcanadiantrolley.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F7eYsJgLzO9ai5Ic9SCmC%2Ftrolley.jpeg?alt=media&amp;token=2ecf9bb9-3da4-4971-b123-1e03c8a02c89">trolley.jpeg</a></td></tr><tr><td><strong>City Sightseeing Prague</strong></td><td>Hp-on hop-off bus tours, river cruises, and guided walking tours, covering major Prague attractions.</td><td><a href="https://www.sightseeingprague.com/">https://www.sightseeingprague.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FWR26Gyu9lGKdcxXIk3Tu%2Fcsprague.jpeg?alt=media&amp;token=a43d0e69-251b-482a-a8fa-6137836e758c">csprague.jpeg</a></td></tr><tr><td><strong>Schönbrunn VR</strong></td><td>Immersive virtual reality experience at Schönbrunn Palace in Vienna.</td><td><a href="https://schoenbrunnvr.com/">https://schoenbrunnvr.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FMsFwPy1jqbggyTxQWSrQ%2Ffilmf.png?alt=media&amp;token=e0376634-1399-455d-8975-7e976b94e887">filmf.png</a></td></tr><tr><td><strong>National Gallery London</strong></td><td>Official National Gallery experiences and private toues.</td><td><a href="https://www.nationalgallery.org.uk/">https://www.nationalgallery.org.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FgyVRxRpg68fQ5j1YAqie%2Fnational%20gallery.jpeg?alt=media&amp;token=c93555bd-da83-4867-8acc-27d91936f3a2">national gallery.jpeg</a></td></tr><tr><td><strong>London City Bus Tours</strong></td><td>Hop On Hop Off tours, private tours, and themed experiences around London.</td><td><a href="https://www.londoncitybustours.com/">https://www.londoncitybustours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FQbgbhi8Ls2UAmXjn7mox%2Flondon%20city%20bus.jpeg?alt=media&amp;token=599906c4-94a2-4363-9b45-07cf22fa04b7">london city bus.jpeg</a></td></tr><tr><td><strong>The Garden At Miserden</strong></td><td>Hstoric walled garden in the Cotswolds.</td><td><a href="https://www.miserden.org/garden/">https://www.miserden.org/garden/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fr7GpvqKojkc0nclnRdww%2Fmiserden.jpeg?alt=media&amp;token=be2f53b8-5caa-4f21-afe5-25a593680b24">miserden.jpeg</a></td></tr><tr><td><strong>Sir Paddy</strong></td><td>High-end tourism and nightlife tours in cities like New York, L.A., and Las Vegas</td><td><a href="https://www.sirpaddy.com/">https://www.sirpaddy.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FfYF5oGglTsNwTayTZCmG%2FSir%20Paddy.jpeg?alt=media&amp;token=69badc27-6878-42f0-bb12-64fc55d44c0a">Sir Paddy.jpeg</a></td></tr><tr><td><strong>Experience Galway</strong></td><td>Walking tours, food tours, pub tours, dark history tours, and whiskey tastings in Galway.</td><td><a href="https://www.experiencegalway.ie/">https://www.experiencegalway.ie/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FkkysUQV2fJK2hwbPsab8%2Fgalway.jpeg?alt=media&amp;token=0ff3df5f-ff17-4aca-87a4-9c1850bf59a7">galway.jpeg</a></td></tr><tr><td><strong>Big City Tourism</strong></td><td>NYC experiences, including the Freedom Liberty Cruise, which eco-friendly boats &#x26; indoor/outdoor seating.</td><td><a href="https://bigcitytourism.com/">https://bigcitytourism.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FMyBUajCPkf7koEawR46A%2FBig%20City%20Tourism.jpeg?alt=media&amp;token=3bab43cd-fee0-470d-8243-3ab3937d6707">Big City Tourism.jpeg</a></td></tr><tr><td><strong>Premium Tours</strong></td><td>Daily London tours, private visits to Stonehenge, day trips to Paris, and Harry Potter studio tours.</td><td><a href="https://www.premiumtours.co.uk/">https://www.premiumtours.co.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FHUAElArifIPpZo0rw0oO%2Fpremium.jpeg?alt=media&amp;token=433ce614-4a12-449f-bae9-b11e89bd6a67">premium.jpeg</a></td></tr><tr><td><strong>Thames River Sightseeing</strong></td><td>Riverboat cruises from Westminster to Greenwich, showcasing iconic landmarks</td><td><a href="https://www.thamesriversightseeing.com/">https://www.thamesriversightseeing.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FEl9p4i3or5PqgGYag0U6%2Fthames-river-sightseeing_river-thames-sightseeing-cruise-image-courtesy-of-thames-river-sightseeing_4cb3fde7a3ad52802f62d9d63221b510.jpg?alt=media&amp;token=3950c09c-c66c-46e3-b567-16ffd8631618">thames-river-sightseeing_river-thames-sightseeing-cruise-image-courtesy-of-thames-river-sightseeing_4cb3fde7a3ad52802f62d9d63221b510.jpg</a></td></tr><tr><td><strong>Tour Dubai</strong></td><td>Now part of Big Bus Tours, operting since 1989 Tour Dubai is one of the emirate’s largest tour operators</td><td><a href="https://tour-dubai.com/">https://tour-dubai.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FLAC7KMRkl0yL2OH0VEh4%2Ftour-dubai2.png?alt=media&amp;token=aa8a33e9-d84d-4cd8-b3e8-6c9300e05135">tour-dubai2.png</a></td></tr><tr><td><strong>Timberbush Tours</strong></td><td>Guided day trips across Scotland from Edinburgh, Glasgow, and Inverness.</td><td><a href="https://www.timberbush-tours.co.uk/">https://www.timberbush-tours.co.uk/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FsRJu1AldSOzbNi9HZa4c%2Ftbush.jpeg?alt=media&amp;token=b2f75990-a921-47a3-95f8-53e07bd807b4">tbush.jpeg</a></td></tr><tr><td><strong>Singapore DUCKtours</strong></td><td>Unique one-hour amphibious vehicle tours, showcasing the city's top landmarks from</td><td><a href="https://www.ducktours.com.sg/">https://www.ducktours.com.sg/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FsdM2adLacYzEjBw8yDsP%2Fsg-ducks.jpeg?alt=media&amp;token=6c537ef1-cfb5-4994-9a65-13cbd80710b6">sg-ducks.jpeg</a></td></tr><tr><td><strong>Tower Tours</strong></td><td>Sightseeing excursions in San Francisco, Muir Woods, Napa and Sonoma aboard luxurious motor coaches.</td><td><a href="https://towertours.com/">https://towertours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FeaXDhom7eXmykYc2BAOW%2Ftower-tours.jpeg?alt=media&amp;token=8a99b0a8-0c56-4fe4-9a7a-7812fa5fca20">tower-tours.jpeg</a></td></tr><tr><td><strong>The Yellow Tours</strong></td><td>Guided tours and excursions in and around Madrid, Toledo, Segovia, Ávila, and Chinchón.</td><td><a href="https://www.theyellowtours.com/">https://www.theyellowtours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2F6uVGNgfQNftizkUmQgiD%2Fyellow-tours.jpeg?alt=media&amp;token=14601559-90bc-44a0-8f7b-2df1e5b19ffc">yellow-tours.jpeg</a></td></tr><tr><td><strong>City Sightseeing New Orleans</strong></td><td>NOLA Hop-on hop-off bus tours with live guided commentary and flexible packages.</td><td><a href="https://citysightseeingneworleans.com/">https://citysightseeingneworleans.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FJhQk2sRSdfQ7mcMwlxv8%2Fcsnola.jpeg?alt=media&amp;token=066da017-a990-4f9c-abad-280243a42a1f">csnola.jpeg</a></td></tr><tr><td><strong>St. Louis Cemetery No. 1 Official Tour</strong></td><td>Guided tours of St. Louis Cemetery No. 1, highlighting its historical tombs and famous residents.</td><td><a href="https://cemeterytourneworleans.com/">https://cemeterytourneworleans.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FwAya3JXWNtgnuTAPTntC%2Fcemetery.jpg?alt=media&amp;token=f4dcdaf2-5300-4473-aa6c-7309cca339de">cemetery.jpg</a></td></tr><tr><td><strong>City Sightseeing Athens</strong></td><td>Hop-on hop-off bus tours covering key Athens attractions.</td><td><a href="https://www.citysightseeing.gr/">https://www.citysightseeing.gr/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FIMusfFWGJcAkUR3TPz6D%2Fcsathens.webp?alt=media&amp;token=c8f27192-9132-40a6-bf68-fc92c86570d5">csathens.webp</a></td></tr><tr><td><strong>Boost Portugal</strong></td><td>Variety of urban tours in Lisbon, including e-bike, Segway, and tuk-tuk tours.</td><td><a href="https://boostportugal.com/">https://boostportugal.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Fur72aMqDoo2oPhs4OfMt%2Fboost.jpeg?alt=media&amp;token=06d452b3-bc8b-4a23-8a1b-d0ce259f027e">boost.jpeg</a></td></tr><tr><td><strong>The Cooltours</strong></td><td>Guided tours across Portugal, including small-group day tours &#x26; transfers.</td><td><a href="https://www.thecooltours.com/">https://www.thecooltours.com/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2Ffh2OF1g2ghcrXxwhVJIY%2Fcooltours.jpeg?alt=media&amp;token=03376244-ef41-4038-b674-75468bbb611a">cooltours.jpeg</a></td></tr><tr><td><strong>Bluedragon Porto City Tours</strong></td><td>Guided experiences in Porto, including walking, bike, Segway, and tuk-tuks.</td><td><a href="https://bluedragon.pt/">https://bluedragon.pt/</a></td><td><a href="https://221588849-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-M7bgGIyO7QYNOfUMfxh%2Fuploads%2FwsSOw4JbuAkLTdHgnrfs%2Fbluedragon.jpeg?alt=media&amp;token=70f25507-cdd9-4ec3-9589-7bfa33005337">bluedragon.jpeg</a></td></tr></tbody></table>


# Other OCTO Implementations

In addition to Ventrata and [our clients](/additional-resources/ventrata-clients), the [OCTO API open standard](https://docs.octo.travel/) is adopted by technology providers across attractions, tours, and activities, including:

* Peek Pro ([octodocs.peek.com](https://octodocs.peek.com/))
* Zaui ([docs.zaui.com/octo](https://docs.zaui.com/octo/))
* Xola
* Anchor

and others.

This reduces the need to build custom integrations for proprietary APIs. You can establish connectivity with a growing set of OCTO-supporting booking and ticketing providers through a single development project.

To learn more about OCTO members and join the initiative yourself, visit <https://www.octo.travel/>.

A volunteer group also tracks known OCTO implementations by suppliers (booking and ticketing platforms) and resellers in this spreadsheet:

[Known OCTO implementations spreadsheet](https://docs.google.com/spreadsheets/d/1UIgUYAPO3SUsdoGmg5xIGHIBHWHOx7XfQCOzOTML6ms/)

{% embed url="<https://docs.google.com/spreadsheets/d/1UIgUYAPO3SUsdoGmg5xIGHIBHWHOx7XfQCOzOTML6ms/edit#gid=0>" %}


# Support

Ventrata provides support for clients and their resellers during API integration and day-to-day operations.

For questions, contact the Connectivity team at <connectivity@ventrata.com>. Response time is typically 1 to 2 business days.

If you need additional support, ask about setting up a shared Slack or Teams channel.


# FAQs

## What's the difference between a voucher and a ticket?

Under each product in the [mapping](/octo-core/products) section, we provide a `deliveryMethods` key. This is an array containing one or both of the following values:

* `VOUCHER`: A single barcode/ticket for the whole booking, regardless of how many tickets were bought.
* `TICKET`: An individual barcode/ticket per person (unit).

Once a booking is confirmed:

* `booking.voucher` is provided if `deliveryMethods` contains `VOUCHER`.
* `booking.units[].ticket` is provided if `deliveryMethods` contains `TICKET`.
* If a method is not available, its value is `null`.

If both are provided, you can use either format based on your user experience and guest preference.

All Ventrata-operated products support both delivery methods, but some attractions require a separate barcode per person. In these situations, you will have only `TICKET` and not `VOUCHER`. Make sure to check `deliveryMethods` for each product.

## Do vouchers/tickets always come with both PDF and QR code? If so, which should I use?

Yes. Ventrata always offers both PDF and QR code delivery formats for vouchers and tickets. If possible, support both: show the QR code in your interface and provide the PDF as a download option. The PDF includes full redemption details.

## What is the difference between `booking.supplierReference` and barcode?

For each booking (and unit/ticket), we provide a QR code value and a supplier reference. In some cases, the barcode is very long and contains enough data to allow it to be verified offline. You should **NOT** print the QR code value in plain text. Instead, print the supplier reference below the QR code, which is always compact and human-readable.


