Skip to main content

Endpoint

GET https://api.voyantcloud.com/v1/products/:id/extensions
Retrieve available add-ons and extensions for a product. Extensions are optional or required add-ons that enhance the base product (e.g., airport transfers, travel insurance, meal upgrades).

Authentication

Authorization
string
required
Bearer token (e.g. Authorization: Bearer YOUR_API_KEY)

Path parameters

id
string
required
Product ID (UUID format)

Request example

curl https://api.voyantcloud.com/v1/products/prod_123abc/extensions \
  -H "Authorization: Bearer YOUR_API_KEY"

Response

extensions
array
required
Array of available extensions
details
object
Map of extension details by product ID
{
  "extensions": [
    {
      "id": "ext_123abc",
      "name": "Airport Transfer",
      "required": false,
      "selectable": true,
      "refProductId": "prod_transfer_456",
      "refSource": "own",
      "hasOptions": false,
      "thumb": "https://cdn.voyantcloud.com/transfers/airport.jpg",
      "pricePerPerson": 25.00,
      "currency": "EUR"
    },
    {
      "id": "ext_789def",
      "name": "Travel Insurance",
      "required": true,
      "selectable": true,
      "refProductId": "prod_insurance_012",
      "refSource": "own",
      "hasOptions": true,
      "thumb": "https://cdn.voyantcloud.com/insurance/standard.jpg",
      "pricePerPerson": 15.00,
      "currency": "EUR"
    }
  ],
  "details": {
    "prod_transfer_456": {
      "description": "Private airport transfer with professional driver",
      "media": [
        {
          "url": "https://cdn.voyantcloud.com/transfers/airport.jpg",
          "alt": null
        }
      ]
    },
    "prod_insurance_012": {
      "description": "Comprehensive travel insurance coverage",
      "media": [
        {
          "url": "https://cdn.voyantcloud.com/insurance/standard.jpg",
          "alt": null
        }
      ]
    }
  }
}

Extension types

Required extensions

Extensions marked as required: true must be included in bookings. These are typically:
  • Travel insurance
  • Visa assistance
  • Mandatory transfers

Optional extensions

Extensions marked as required: false are optional add-ons:
  • Meal upgrades
  • Excursions
  • Room upgrades
  • Equipment rental

Extensions with options

When hasOptions: true, the extension references a product with multiple pricing options (e.g., different insurance tiers, room types).

Use cases

Display add-ons in booking flow

Show available extensions with pricing:
async function loadProductExtensions(productId) {
  const response = await fetch(`https://api.voyantcloud.com/v1/products/${productId}/extensions`, {
    headers: { Authorization: `Bearer ${process.env.VOYANT_API_KEY}` },
  })

  const { extensions, details } = await response.json()

  return extensions.map((ext) => ({
    id: ext.id,
    name: ext.name,
    required: ext.required,
    price: ext.pricePerPerson
      ? `${ext.currency} ${ext.pricePerPerson.toFixed(2)}/person`
      : "Price varies",
    description: details[ext.refProductId]?.description || "",
    image: ext.thumb,
    hasOptions: ext.hasOptions,
  }))
}

Calculate total with addons

Include selected extensions in price calculation:
async function calculateWithAddons(productId, departureId, pax, selectedExtensions) {
  const response = await fetch(
    `https://api.voyantcloud.com/v1/departures/${departureId}/price`,
    {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VOYANT_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      productId,
      pax,
      addons: selectedExtensions.map((ext) => ({
        id: ext.id,
        quantity: ext.quantity,
      })),
    }),
    },
  )

  return response.json()
}

Validate required extensions

Ensure required extensions are selected:
function validateExtensions(extensions, selectedIds) {
  const required = extensions.filter((ext) => ext.required)
  const missing = required.filter((ext) => !selectedIds.includes(ext.id))

  if (missing.length > 0) {
    throw new Error(`Missing required extensions: ${missing.map((e) => e.name).join(", ")}`)
  }

  return true
}
Pre-select required extensions in your booking UI to improve user experience.