Workspace API
A REST API that lets external booking engines and partner systems browse trips, check availability, and create orders in your workspace.
The Workspace API is a REST interface that allows external applications -- such as custom booking websites, partner systems, or CRM integrations -- to interact with your workspace programmatically. Through the API, external systems can browse your trips, check real-time availability and pricing, and create fully processed orders with automatic payment link generation.
How It Works
External applications authenticate using an API key included in every request. Once authenticated, they can list your trips, retrieve detailed product and pricing information, check availability for specific participant combinations, and submit orders. When an order is created through the API, Itsy handles everything automatically: client record creation, pricing calculation, payment link generation, and confirmation email delivery.
Authentication
Every request must include your API key in the x-api-key header. The key identifies your workspace and enforces the configured rate limit. See API Keys for how to create, rotate, and revoke keys.
Requests without a valid key receive a 401 Unauthorized response. Requests with a revoked or expired key are also rejected. If your integration suddenly stops working, check the key's status on the API Keys page -- it may have expired or been revoked.
Available Endpoints
All endpoints are prefixed with /v1/. The full base URL depends on your environment.
Labels
List Labels
GET /v1/labels
Retrieve all active labels in your workspace. Labels are used to tag and categorize trips. External systems can use these labels to filter trips or build themed booking experiences.
Each label in the response includes its name and slug. Use the slug values when filtering trips by label.
Trip Categories
List Trip Categories
GET /v1/trips/categories
Retrieve all active trip categories in your workspace. Trip categories let you organize trips into groups such as "Day Tours", "Multi-day Adventures", or "Cruises".
Each category in the response includes its name and slug. Use the slug values when filtering trips by category.
Trips
List Trips
GET /v1/trips
Retrieve all bookable trips in your workspace with optional filters.
| Parameter | Type | Description |
|---|---|---|
| departingFrom | Date (optional) | Only trips departing on or after this date |
| departingTo | Date (optional) | Only trips departing on or before this date |
| labels | Repeated string (optional) | One or more label slugs to filter by |
| categories | Repeated string (optional) | One or more category slugs to filter by |
| page | Number (optional) | Page number, starting at 1 |
| pageSize | Number (optional) | Items per page (default 25, max 100) |
Only static trips with future departures are returned. Trips are filtered by their departure date, and only those departing on or after today are included. When departingFrom is supplied, the cutoff uses the later of the two dates: only trips departing on or after max(today, departingFrom) are returned. A departingFrom in the past has no effect (the today cutoff applies), while a departingFrom in the future overrides today.
Both labels and categories accept repeated query parameters to pass multiple values -- for example, ?labels=slug1&labels=slug2&categories=day-tours. Multiple values for the same filter are ORed together (match any of the listed label slugs, or any of the listed category slugs), while different filters are ANDed (trips must match the labels filter and the categories filter). Comma-separated values in a single parameter are not supported.
Each trip in the response includes:
| Field | Description |
|---|---|
| id | The trip's unique identifier (GUID) |
| name | Trip display name |
| slug | URL-friendly identifier used in other endpoints |
| type | Trip type |
| departingOn | Departure date |
| length | Trip length in days (null for duration-based trips) |
| useDurations | Whether the trip uses duration-based pricing |
| durations | Available duration options (for duration-based trips) |
| category | Trip category with name and slug |
| labels | Assigned label names and slugs |
| depositInfo | Deposit configuration, split into terms and eligibility (see below) |
| bookingCutoffInDays | Days before departure when booking closes |
| capacity | Planned and booked participant counts, or null when the trip has no planned capacity (see below) |
| participantLimits | The participant limits the API enforces on this trip, or null when it enforces none (see below) |
| priceExamples | Pre-calculated prices for common party sizes, sorted by adults then children then duration. Only includes examples that are currently bookable -- past-cutoff, uncalculated, and (on enforcing trips) outside-the-limits parties are excluded. See Price examples below. |
The depositInfo object separates the deposit terms configured for the trip from whether a deposit can be taken today:
| terms | Description |
|---|---|
| isEnabled | Whether the trip is configured to accept deposits |
| baseAmount | The deposit base. A rate, not a price: for PrPax it is multiplied by the party size, then capped at the order total |
| calculationType | PrPax (per participant) or PrOrder (per order) |
| depositAllowedUntil | The last date a deposit may be taken, inclusive |
| balanceDueOn | The date the full balance falls due |
| eligibility | Description |
|---|---|
| isEligible | Whether a deposit may be taken today |
| closedReason | Why not, when isEligible is false (e.g. WithinCutoff) |
A trip can have isEnabled: true while isEligible is false — deposits are configured, but departure is already too near. Decide from isEligible, describe from terms. Neither field accounts for price: a deposit at or above the order total is charged in full, so confirm with the availability endpoint before quoting an amount.
The capacity object lets you show how full a trip is, for example "12 of 20 booked":
| Field | Description |
|---|---|
| planned | How many participants the trip is planned to carry |
| booked | Participants on active bookings |
Planned capacity is advisory. It does not limit bookings, so booked can be higher than planned. It is only returned when a planned capacity is set on the trip; otherwise capacity is null.
The participantLimits object describes who one order may carry, so a booking form can offer only parties the trip accepts:
| Field | Description |
|---|---|
| maxAdults | Most adults per order, or null for no cap |
| childrenAllowed | Whether an order may include children |
| maxChildren | Most children per order, or null for no cap |
| infantsAllowed | Whether an order may include infants |
| maxInfants | Most infants per order, or null for no cap |
It is only returned on trips where Also enforce in the workspace API is switched on under the trip's Participants conditions; otherwise participantLimits is null and the API does not enforce the trip's participant limits. On an enforcing trip every order also needs at least one adult, and price examples for parties outside the limits are left out.
Price examples
Each trip in the response includes a priceExamples array showing pre-calculated prices for common party sizes. These are the price examples configured on the trip (seeded from the workspace default parties in Booking Process settings).
| Field | Description |
|---|---|
| adults | Number of adults in the party |
| children | Number of children in the party |
| duration | The duration priced, for trips that use duration-based pricing (null otherwise) |
| price | Gross, VAT-inclusive total for the party, in the workspace currency |
Only examples that are currently bookable are included. Examples whose party cannot be booked (because the booking cutoff has passed, the price has not been calculated, or the party exceeds enforced participant limits) are excluded rather than returned with null prices. The array is sorted by adults, then children, then duration.
Use price examples for display purposes -- showing customers indicative "from" pricing or a price grid before they start the full booking flow. For exact pricing tied to a specific product selection, use the Get Trip Products or Check Availability endpoints.
Get Trip Details
GET /v1/trips/{slug}
Retrieve information for a single trip by its slug. The response includes the same fields as the list endpoint. Use this when you need to look up a specific trip by its URL slug rather than browsing the full list.
To get products and pricing, use the Get Trip Products endpoint with a participant combination.
Get Trip Products
GET /v1/trips/{slug}/products
Retrieve the products available on a trip, with pricing calculated for a specific participant combination. Unlike Get Trip Details, this endpoint accepts participant counts so prices reflect the actual booking scenario.
| Parameter | Type | Description |
|---|---|---|
| slug | Path string | The trip slug |
| adults | Query number | Number of adult participants |
| children | Query number | Number of child participants |
| infants | Query number | Number of infant participants |
The response includes product groups and ungrouped products, each with rate details, capacity, current availability, variants, and duration-specific pricing.
Get Field Requirements
GET /v1/trips/{slug}/fields
Retrieve the data fields required for clients and participants when booking a specific trip. The response contains two field maps:
| Field Map | Description |
|---|---|
| client | Fields for the booking client (e.g., first name, last name, email, phone). Each field is true if required, false if optional. |
| participant | Fields for each participant (e.g., name, passport number, nationality, date of birth). Each field is true if required, false if optional. |
If the trip has custom field overrides, those take precedence over workspace defaults. This endpoint helps external booking forms collect the right information before submitting an order.
Check Availability
POST /v1/trips/{slug}/availability
Submit a participant combination and product selections to validate availability and get a price calculation.
What you send:
| Field | Description |
|---|---|
| adults | Number of adult participants |
| children | Number of child participants |
| infants | Number of infant participants |
| duration | Selected duration (for duration-based trips) |
| products | List of product selections, each with a product ID, optional variant ID, and participant counts or indexes |
What you receive:
| Field | Description |
|---|---|
| isValid | Whether the booking is still available (checks capacity and booking cutoff) |
| errorMessage | Reason if the booking is not valid |
| capacity | The trip's planned and booked participant counts, or null when no planned capacity is set (same shape as on the trip) |
| deposit | Deposit details (see below) |
| lineItems | Per-product breakdown with product ID, name, type, availability status, price, and variant-level pricing |
The deposit object includes:
| Field | Description |
|---|---|
| isAllowed | Whether a deposit payment is available for this booking |
| disallowedReason | Why deposits are not available (e.g., departure too soon) |
| amount | Deposit amount to collect |
| balanceDue | Remaining amount after the deposit |
| balanceDueOn | Date when the remaining balance is due |
| fullPaymentDueDayCount | Days before departure when full payment is required |
| daysUntilDeparture | Days until the trip departs |
Use this before creating an order to show customers accurate pricing and confirm availability.
On a trip that enforces its participant limits, a party outside them (for example six adults when the trip allows four) is refused with a 400 Bad Request naming the broken limit, rather than a response with isValid: false. Only the top-level adults, children and infants are checked.
Get Seat Maps
GET /v1/trips/{slug}/seats
Retrieve seat maps for one or more products on a trip. Products that have a seating layout return their seat grid with per-seat availability and pricing.
| Parameter | Type | Description |
|---|---|---|
| slug | Path string | The trip slug |
| products | Query string | Comma-separated list of product IDs to fetch seat maps for |
At least one product ID is required. Products without a seat map are silently omitted from the response.
Each seat map in the response includes:
| Field | Description |
|---|---|
| productId | The product this seat map belongs to |
| totalRows | Number of rows in the layout |
| totalColumns | Number of columns in the layout |
| seatSelectionMode | How seats are selected (e.g., manual pick or automatic assignment) |
| totalSeats | Total seats in the layout |
| availableSeats | Seats currently available for booking |
| seats | List of individual seats with row, column, label, per-participant-type rates, characteristics, and availability status |
Use the Get Trip Products endpoint first to determine which products have a seat map (via the hasSeatMap flag), then request seat maps only for those products.
Orders
Create Order
POST /v1/orders
Submit a complete order with client details, participants, and product selections. Itsy processes the order end-to-end:
- Client matching -- If a client with the same email exists, the existing record is used. Otherwise, a new client is created.
- Participant creation -- All travelers are added to the order with their details.
- Pricing calculation -- Product prices are calculated based on rate types, participant counts, and any promo codes.
- Payment setup -- If a payment provider is configured, a payment link or form data is generated for the selected payment intention (full payment or deposit).
- Confirmation email -- An order confirmation email is automatically sent to the client.
- Event publishing -- Events are published for any configured actions (e.g., triggers on external order creation).
On a trip that enforces its participant limits, an order whose party is outside them is refused before any of this happens, with the same message the availability check gives.
What you send:
| Field | Description |
|---|---|
| tripId | The trip ID (GUID) to book |
| adults | Number of adult participants |
| children | Number of child participants |
| infants | Number of infant participants |
| duration | Selected duration (for duration-based trips) |
| products | Selected products, each with product ID, optional variant ID, and participant assignments |
| client | Client details: first name, last name, email, and optional phone and unique ID |
| participants | Participant details: type (adult/child/infant), name, and optional fields (email, phone, gender, nationality, address, passport details, date of birth) |
| comment | Optional free-text note attached to the order |
| promoCode | Optional discount code |
| paymentIntention | PayInFull or PayPartially. PayPartially charges the deposit; it falls back to the full price when the trip or workspace does not allow deposits. |
| urls | Optional redirect targets for the payment gateway: success, canceled, and error. See Custom payment redirects. |
What you receive:
| Field | Description |
|---|---|
| orderId | The created order's unique identifier |
| orderCode | Human-readable order reference code |
| price | Total order price |
| depositAmount | Deposit amount (if deposit payment was selected) |
| status | Order status |
| paymentStatus | Payment status |
| paymentProvider | The payment provider used (Stripe, Rapyd, Teya, or Straumur). Valitor is a legacy provider and is intentionally excluded from Workspace API responses. |
| paymentUrl | URL to redirect the customer to for payment (if applicable) |
| paymentFormData | Form data for payment providers that use form submission instead of URL redirect |
| createdOn | Order creation timestamp |
| startingOn | Trip start date |
| endingOn | Trip end date |
| fullyPaidOn | Date the order was fully paid (null until paid) |
| conflicts | Non-fatal issues that occurred during order creation but did not prevent it (e.g., a seat reservation that lost a race to another booking). Empty on a clean success. |
Custom payment redirects
By default the payment gateway returns the payer to the order page hosted on your Itsy customer portal. Send a urls object to send them somewhere of your own instead — your booking confirmation page, your basket, your own error screen:
{
"tripId": "...",
"paymentIntention": "PayInFull",
"urls": {
"success": "https://yoursite.com/booking/thank-you",
"canceled": "https://yoursite.com/booking/cart",
"error": "https://yoursite.com/booking/payment-failed"
}
}Every field is optional and each falls back on its own, so you can override one outcome and keep the Itsy order page for the rest. Each URL must be an absolute http or https address of at most 2048 characters; anything else fails the request.
Placeholders
Your landing page usually needs to know which order it is looking at. Write a placeholder into the URL and Itsy fills it in when it builds the payment link:
| Placeholder | Value |
|---|---|
{orderId} | The created order's unique identifier |
{orderCode} | The human-readable order reference code |
{paymentId} | The identifier of the payment the link was created for |
Put them wherever you need them -- in the path, the query string, or both:
{
"urls": {
"success": "https://yoursite.com/booking/{orderCode}/thank-you?ref={orderId}",
"canceled": "https://yoursite.com/booking/cart?order={orderId}",
"error": "https://yoursite.com/booking/payment-failed?payment={paymentId}"
}
}Values are URL-encoded as they are substituted, so a reference code containing a space or a slash cannot break the address. The 2048-character limit is measured after substitution.
Placeholder names are case-sensitive, and only the three above exist. Anything else -- {orderid}, {order_id}, or an unmatched brace -- fails the request with a message naming the supported placeholders, rather than sending the payer to a URL with a literal {orderid} in it.
Not every gateway supports all three targets:
| Provider | success | canceled | error |
|---|---|---|---|
| Valitor | Yes | Yes | Not supported -- the payment form has no error target |
| Teya | Yes | Yes | Yes |
| Rapyd | Yes | Yes | Yes |
| Stripe | Yes | Yes | Not supported -- a declined card keeps the payer on the Stripe page |
| Straumur | Yes | Not supported -- one return URL covers every outcome | Not supported |
These redirects only move the payer's browser. The server-to-server payment confirmation always goes to Itsy, so payments are registered against the order however you redirect the payer.
Find Order
GET /v1/orders/public-url
Look up an order by its code and client email, and receive a public URL where the customer can view their order. This is useful for building "find my order" flows in external booking engines.
| Parameter | Type | Description |
|---|---|---|
| code | Query string | The order reference code |
| Query string | The client's email address |
The response is the public URL for the order. If no matching order is found, a 404 Not Found is returned.
Get Order
GET /v1/orders/{orderId}
Retrieve the current status of an order created through the API. Use the order ID returned from the Create Order response.
| Field | Description |
|---|---|
| orderId | The order's unique identifier |
| orderCode | Human-readable order reference code |
| price | Total order price |
| depositAmount | Deposit amount |
| status | Current order status |
| paymentStatus | Current payment status |
| createdOn | Order creation timestamp |
| startingOn | Trip start date |
| endingOn | Trip end date |
| fullyPaidOn | Date the order was fully paid (null until paid) |
Rate Limiting
Each API key has a configured rate limit (requests per minute). Requests exceeding the limit receive an error response. You can adjust the rate limit from the API Keys settings page.
What the API Can and Cannot Do
Can do:
- List available labels and trip categories
- Browse and filter trips by date range, labels, and categories, with pre-calculated price examples
- Retrieve full product and pricing details for a specific participant combination
- Retrieve seat maps with per-seat availability and pricing for products with seating layouts
- Check real-time availability and get accurate deposit calculations
- Retrieve field requirements for booking forms (client and participant fields)
- Create orders with automatic client matching, payment link generation, and confirmation emails
- Look up an order by code and email to get its public URL
- Track order status and payment status
Cannot do:
- Modify or cancel existing orders, trips, or products
- Access sensitive payment instrument details (e.g., full card numbers, CVV, bank account numbers); non-sensitive fields such as
price,depositAmount, andpaymentStatusremain available. - Manage clients or participants independently of orders
- Access data from other workspaces
- Bypass rate limits or authentication
How It Connects
- API Keys -- Each API key grants access to one workspace's API with a configured rate limit and environment.
- Trips -- The API exposes your trips, products, pricing, and price examples for external consumption.
- Orders -- Orders created through the API appear in your admin interface like any other order, with the origin marked as "Workspace API". Each order tracks which API key created it for auditing purposes.
- Actions -- Order creation triggers configured actions, so automations work the same for API-created orders.
- Payment Providers -- The API generates payment links using your configured payment provider (Stripe, Rapyd, Teya, or Straumur). Valitor is a legacy provider and is intentionally excluded from Workspace API responses.
- Labels -- External systems can list all labels and filter trips by label slugs to build themed or filtered booking experiences.
- Trip Categories -- External systems can list all categories and filter trips by category slugs to present organized booking options.
- Workspace Settings -- Price example default parties configured in Booking Process settings seed each new trip's price examples, which the API publishes on the trip listing.