Skip to content

Products

Products are the sellable catalog items that you expose to guests. A product combines a unit type, rate configuration, target inventory goals, and optional services into one offer that can be used in your booking flows.

Products sit under Product Groups. Product groups define shared commercial controls, while products represent the individual offers within those groups.

A product combines:

  • A unit type (unitType)
  • A product group (productGroup)
  • A rate (rate) with interval and rate calendars
  • Target inventory settings (targetUnitCount, targetOccupancyPercentage)
  • Optional and included services

CatalogProductProductTypeEnum defines the product category:

Value Description
MULTI_FAMILY Product configured for multi-family use cases
SHORT_STAY Product configured for short stay use cases
STUDENT Product configured for student use cases

CatalogRateIntervalEnum controls the pricing interval:

Value Description
MONTHLY Monthly pricing
NIGHTLY Nightly pricing
WEEKLY Weekly pricing
Field Type Description
id ID! Product identifier
targetUnitCount Int! Target number of units for this product
targetOccupancyPercentage Float! Target occupancy percentage for this product
productGroup ProductGroup! Product group the product belongs to
productGroupId ID! Product group identifier, deprecated in favor of productGroup.id
unitType UnitType Unit type linked to the product
rate ProductRate Rate linked to the product
services ProductServiceConnection! Services currently selected for the product
eligibleServices ServiceConnection! Services that can be added to the product
allocatedUnits AllocatedUnitConnection! Units allocated to the product
Field Type Description
id ID! Product rate identifier
interval CatalogRateIntervalEnum! Rate interval (MONTHLY, NIGHTLY, WEEKLY)
productId ID Related product identifier
Field Type Description
id ID! Product service identifier
service Service! Referenced service
serviceOffering CatalogProductServiceOfferingEnum! Whether the service is included or optional
createdAt ISO8601DateTime! Creation timestamp
updatedAt ISO8601DateTime! Last update timestamp
query Product($id: ID!, $first: Int, $after: String) {
catalog {
product(id: $id) {
id
targetUnitCount
targetOccupancyPercentage
productGroup {
id
internalReference
}
unitType {
id
code
}
rate {
id
interval
calendars(first: $first, after: $after) {
nodes {
id
startDate
endDate
amountCents
currency
}
totalCount
pageInfo {
hasNextPage
endCursor
}
}
}
services(first: $first, after: $after) {
nodes {
id
serviceOffering
service {
id
name
amountCents
amountCurrency
applicationUnit
}
}
totalCount
}
eligibleServices(first: $first, after: $after) {
nodes {
id
name
amountCents
amountCurrency
applicationUnit
}
totalCount
}
}
}
}
{
"id": "product-id",
"first": 20
}
query ProductGroupProducts($id: ID!, $first: Int, $after: String) {
catalog {
productGroup(id: $id) {
id
internalReference
products(first: $first, after: $after) {
nodes {
id
targetUnitCount
targetOccupancyPercentage
unitType {
id
code
}
rate {
id
interval
}
}
totalCount
pageInfo {
hasNextPage
endCursor
}
}
}
}
}
{
"id": "product-group-id",
"first": 20
}
mutation CreateProduct($input: CreateProductMutationInput!) {
catalog {
product {
create(input: $input) {
id
}
}
}
}
{
"input": {
"product": {
"name": "Standard Studio Product",
"productGroupId": "product-group-id",
"productType": "STUDENT",
"targetUnitCount": 20,
"targetOccupancyPercentage": 95,
"unitTypeId": "unit-type-id",
"rate": {
"amountCents": 125000,
"currency": "GBP",
"interval": "WEEKLY"
}
}
}
}

Required fields for product in CreateProductMutationInput:

Field Type
name String!
productGroupId ID!
productType CatalogProductProductTypeEnum!
targetUnitCount Int!
unitTypeId ID!
rate CreateRateInput!
mutation UpdateProduct($input: UpdateProductMutationInput!) {
catalog {
product {
update(input: $input) {
id
}
}
}
}
{
"input": {
"productId": "product-id",
"product": {
"targetUnitCount": 24,
"targetOccupancyPercentage": 97.5
}
}
}

Required fields for UpdateProductMutationInput:

Field Type
productId ID!
product ProductUpdateInput!
mutation DeleteProduct($input: DeleteProductMutationInput!) {
catalog {
product {
delete(input: $input) {
id
}
}
}
}
{
"input": {
"productId": "product-id"
}
}

Required fields for DeleteProductMutationInput:

Field Type
productId ID!

Tip: The Catalog product namespace also supports service management (addServices, removeService, updateService) and unit allocation (allocateUnits, unallocateUnits), plus rate updates through catalog.rate.update.

If you use MCP, these tools are relevant:

See Tools for setup and full tool coverage.

Products do not own contract date boundaries directly — they inherit them from their parent product group. The contractEarliestStartDate, contractLatestStartDate, contractEarliestEndDate, and contractLatestEndDate fields on ProductGroup control the date range a booking made against any product in the group can occupy.

In particular, contractEarliestStartDate and contractLatestEndDate are the outer bounds, while contractLatestStartDate and contractEarliestEndDate allow a student to start late or end early within those bounds. See Contract windows on the Product Group doc for full details.

  • A product belongs to a Product Group
  • A product references a Unit Type
  • A product includes rate information that works with Pricing
  • Product details are used as part of the Ecommerce booking flow