More products

Activities

Activities are searched by destination and date. Each result is one way to do the activity — a language, a ticket type, a time slot — priced for the whole party.

Find a destination

Activity searches need a destination code. Look it up by name:

Request · cURL
curl "https://api.roaveagents.com/api/v1/destinations?productType=activity&q=barcel" \
  -H "X-API-Key: $ROAVE_API_KEY"
Response · 200 (abridged)
{
  "data": {
    "items": [
      { "_id": "66e0f1a2b3c4d5e6f7a8b9c0", "kind": "activity_destination", "code": "BCN",
        "name": "Barcelona", "cityName": "Barcelona", "countryCode": "ES" }
    ],
    "nextCursor": null
  },
  "meta": {},
  "error": null
}

Destination codes differ between inventory sources, so one name can return several rows. Send the code from the row you picked exactly as returned; don't build codes yourself.

To show what's available before a traveller picks dates, browse a destination's catalogue with GET /destinations/:code/activities. It lists activity names and images, without prices.

POST /search body
{
  "productType": "activity",
  "destination": "Barcelona",
  "destinationCode": "BCN",
  "checkIn": "2026-11-04",
  "occupancy": [{ "adults": 2, "childrenAges": [10] }],
  "currency": "EUR",
  "market": "GB"
}
  • destination (the name) is required, and destinationCode makes it precise. Without a code, an unrecognised name returns 400 unknown_destination.
  • checkIn is the activity date.
  • Put everyone in one occupancy entry, with every child's age — prices are often per age band.

Activity searches finish before POST /search returns.

Results

Each row is one option — a modality and, where relevant, a session time — for one activity. Read with groupByProduct=true to page by activity (group the rows by canonicalProductId for your listing), then POST /search/:id/products/:productId/rates to list every option for the activity the traveller opens.

A result row (abridged)
{
  "canonicalProductId": "66e0f1a2b3c4d5e6f7a8c111",
  "rateQuoteId": "66f2b3d4e4b0c1d2e3f4d200",
  "sellAmountMinor": 14800,
  "sellCurrency": "EUR",
  "refundable": true,
  "summary": {
    "activityName": "Sagrada Família skip-the-line tour",
    "modalityName": "Guided tour in English",
    "session": "10:00",
    "durationText": "2 hours",
    "operationDate": "2026-11-04",
    "cancellationPolicy": {
      "refundable": true,
      "deadlines": [{ "before": "2026-11-03T10:00:00Z", "penaltyMinor": 14800, "currency": "EUR" }]
    }
  }
}

Not every activity has a modality, session or operation date; those fields are null when the inventory doesn't provide them.

Use GET /quotes/:id/details for the full description and images, plus highlights, important information and how to redeem the ticket where the operator provides them. Show the important information and redemption instructions before the traveller books.

Choose an option

Some activities come back as a single row with a “from” price and no time slot. The real options — each time slot, language or ticket type — are only known once you ask. For those, list them before you price-check:

Request · cURL
curl -X POST "https://api.roaveagents.com/api/v1/quotes/66f2b3d4e4b0c1d2e3f4d200/activity-recheck" \
  -H "X-API-Key: $ROAVE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{}'
Response · 200 (abridged)
{
  "data": {
    "quoteId": "66f2b3d4e4b0c1d2e3f4d200",
    "bookableOptions": [
      {
        "supplierRateRef": "rr_q3Jd8Lr2mT0vX9aQe7Kc1bYw",
        "reference": "OPT-1",
        "title": "Guided tour in English",
        "timeSlot": "10:00",
        "language": "en",
        "price": { "amountMinor": 14800, "currency": "EUR" },
        "cancellationPolicy": { "refundable": true, "deadlines": [] },
        "panRequired": false,
        "bookingQuestions": []
      }
    ]
  },
  "meta": {},
  "error": null
}
  • price is what you'll pay for that option, worked out the same way the price-check prices it. It can be missing when an option can't be priced yet; show “priced on selection” and let the price-check give the figure.
  • supplierRateRef is an opaque token. Send it back unchanged; don't store it beyond the quote's 20-minute life.
  • If the party changed since the search, send it as occupancy in the body to list options for the new party.
  • Activities that don't have separate options return 400 activity_recheck_unsupported — price-check the row directly.

Then price-check the option the traveller chose by sending its token:

POST /quotes/:id/price-check body
{ "supplierRateRef": "rr_q3Jd8Lr2mT0vX9aQe7Kc1bYw" }

From then on the quote books that option. A token that has been altered is refused with 400 validation_error, and a token from a different quote with 400 rate_option_not_offered. When an option has panRequired: true, send panNumber when you book.

Price-check

Price-check the row — or, after choosing an option, send its token as supplierRateRef. If the party changed since the search, send the new party as occupancy in the price-check body to reprice it; if the option can't take that party you get 409 pax_mix_unavailable.

Some activities ask questions the operator needs answered — a pickup hotel, dietary needs. When they do, the price-check's quote.details includes bookingQuestions. Answer them in bookingAnswers when you book, keyed by question code, or by CODE:n for per-traveller questions (n counts travellers from 1):

bookingAnswers
"bookingAnswers": {
  "PICKUP_HOTEL": "Hotel Example, Passeig de Gràcia 1",
  "DIETARY:1": "Vegetarian",
  "DIETARY:2": "None"
}

A missing mandatory answer returns 400 booking_answer_required.

Book

  • Send one traveller per participant. Every traveller needs an age, adults included — operators price and admit by age. Adults need a whole-number age from 18 to 120; otherwise the booking returns 400 traveler_manifest_mismatch.
  • The lead traveller needs email and phone; the operator uses them on the day.
  • Always send a title on the lead traveller (Mr, Mrs, Ms, Miss, Master or Dr). Some activities need it, the quote doesn't say which, and without it they return 400 traveler_title_required.
  • Pay with paymentMethod: "credit". Activities are sold net.

Activities usually confirm straight away. If one returns supplier_pending, the operator is still confirming — see Booking statuses.

The operator's voucher

When the operator issues one, a confirmed activity carries the operator's own voucher in the line item's details.supplierVouchers. That voucher is the ticket. Give it to the traveller unchanged; a voucher you design yourself isn't accepted for entry on its own.

Cancel

Cancel with POST /bookings/:id/cancel. Many activities are free to cancel until a day or two before; check cancellationPolicy first, as described in Cancellations and refunds.