Skip to content

Product Groups

Product groups let you manage a set of related products as one catalog unit. You can use them to control contract windows, activation state, publishing windows, and booking expiry settings across multiple products.

In practice, a product group helps you organise products that should follow the same commercial rules. This is useful when you want consistent configuration for a cohort of products instead of updating each product one by one.

Each product group has contract date boundaries:

  • contractEarliestStartDate
  • contractLatestStartDate
  • contractEarliestEndDate
  • contractLatestEndDate

contractEarliestStartDate and contractLatestEndDate are the outer bounds that control the overall date range a booking can be made over for products in this group. No booking can start before contractEarliestStartDate or end after contractLatestEndDate.

contractLatestStartDate and contractEarliestEndDate define the inner flexibility within those outer bounds:

  • A booking can start anywhere between contractEarliestStartDate and contractLatestStartDate (e.g. a student arriving late).
  • A booking can end anywhere between contractEarliestEndDate and contractLatestEndDate (e.g. a student leaving early).

In other words, the full window a booking may occupy is [contractEarliestStartDate, contractLatestEndDate], while the start date must fall in [contractEarliestStartDate, contractLatestStartDate] and the end date must fall in [contractEarliestEndDate, contractLatestEndDate].

A product group has two related controls:

  • Activation state (ACTIVE, INACTIVE)
  • Publishing window (startDate, endDate) with a publishing state

You can update activation state for one or more product groups in a single mutation.

Product groups can be classified by segment to indicate the type of student accommodation they represent. The productSegment field is optional and applies to student product groups only.

Value Description
FULL_YEAR Accommodation spanning the full calendar year including summer
ACADEMIC_YEAR Accommodation covering the full academic year, excluding summer
SEMESTER_1 Accommodation for the first semester of the academic year only
SEMESTER_2 Accommodation for the second semester of the academic year only

Omit productSegment for non-student product groups.

A product group contains a connection of products. This lets you inspect the products that belong to the group and paginate through them.

Field Type Description
id ID! Product group identifier
internalReference String! Internal reference string for the group
workspaceId Integer! Workspace identifier
contractEarliestStartDate String! Earliest contract start date
contractLatestStartDate String! Latest contract start date
contractEarliestEndDate String! Earliest contract end date
contractLatestEndDate String! Latest contract end date
defaultExpiryDurationInSeconds Integer Default booking expiry duration
allowBookingExpiryTimer Boolean Whether booking expiry timer is enabled
academicYear String Academic year in YYYY/YYYY format
productSegment CatalogProductSegmentEnum Segment classification (student products only)
state CatalogProductGroupStateEnum! Activation state
publishing Publishing! Publishing window and lifecycle state
requiresCancelationPolicy Boolean! Whether a cancellation policy is required for this product group
contractTemplateExternalId String External contract template identifier
createdAt ISO8601DateTime! Creation timestamp
updatedAt ISO8601DateTime! Last update timestamp
Value Description
ACTIVE Product group is active
INACTIVE Product group is inactive
Value Description
FULL_YEAR Accommodation spanning the full calendar year including summer
ACADEMIC_YEAR Accommodation covering the full academic year, excluding summer
SEMESTER_1 Accommodation for the first semester of the academic year only
SEMESTER_2 Accommodation for the second semester of the academic year only
Value Description
SCHEDULED Publishing has not started yet
ONGOING Publishing is currently active
FINISHED Publishing window has ended
query ProductGroup($id: ID!) {
catalog {
productGroup(id: $id) {
id
internalReference
state
productSegment
publishing {
startDate
endDate
state
}
products {
totalCount
}
}
}
}
{
"id": "product-group-id"
}
query ProductGroups(
$filters: ProductGroupsFiltersInput
$first: Int
$after: String
) {
catalog {
productGroups(filters: $filters, first: $first, after: $after) {
nodes {
id
internalReference
state
}
totalCount
pageInfo {
hasNextPage
endCursor
}
}
}
}
{
"filters": {
"state": "ACTIVE",
"published": true
},
"first": 20
}

Tip: productGroups follows the standard connection pattern. Use cursors for pagination when iterating through large catalogs.

mutation CreateProductGroup($input: CreateProductGroupMutationInput!) {
catalog {
productGroup {
create(input: $input) {
id
}
}
}
}
{
"input": {
"productGroup": {
"internalReference": "PG-2026-01",
"contractEarliestStartDate": "2026-01-01",
"contractLatestStartDate": "2026-09-30",
"contractEarliestEndDate": "2026-01-15",
"contractLatestEndDate": "2027-08-31",
"workspaceId": "workspace-id",
"academicYear": "2026/2027",
"productSegment": "ACADEMIC_YEAR",
"allowBookingExpiryTimer": true,
"defaultExpiryDurationInSeconds": 1800,
"publishing": {
"startDate": "2026-02-01",
"endDate": "2027-06-30"
}
}
}
}

Required fields for productGroup in create:

Field Type
internalReference String!
contractEarliestStartDate ISO8601Date!
contractLatestStartDate ISO8601Date!
contractEarliestEndDate ISO8601Date!
contractLatestEndDate ISO8601Date!
workspaceId ID!
academicYear String!

Optional fields for productGroup in create:

Field Type Description
allowBookingExpiryTimer Boolean Whether booking expiry timer is enabled
defaultExpiryDurationInSeconds Integer Default booking expiry duration in seconds
productSegment CatalogProductSegmentEnum Segment classification (student products only)
cancelationPolicyId ID ID of the cancellation policy to associate
requiresCancelationPolicy Boolean Whether a cancellation policy is required
contractTemplateExternalId String External contract template identifier
publishing PublishingInput Publishing window configuration
mutation UpdateProductGroup($input: UpdateProductGroupMutationInput!) {
catalog {
productGroup {
update(input: $input) {
id
}
}
}
}
{
"input": {
"productGroupId": "product-group-id",
"productGroup": {
"internalReference": "PG-2026-01-REV1",
"productSegment": "SEMESTER_1",
"publishing": {
"startDate": "2026-03-01",
"endDate": "2027-07-31"
}
}
}
}

Required fields for update input:

Field Type
productGroupId ID!
productGroup ProductGroupUpdateInput!

All fields within productGroup are optional for update. Key settable fields include:

Field Type Description
internalReference String Internal reference string
cancelationPolicyId ID ID of the cancellation policy to associate
requiresCancelationPolicy Boolean Whether a cancellation policy is required
allowBookingExpiryTimer Boolean Whether booking expiry timer is enabled
defaultExpiryDurationInSeconds Integer Default booking expiry duration in seconds
productSegment CatalogProductSegmentEnum Segment classification (student products only)
contractTemplateExternalId String External contract template identifier
publishing PublishingInput Publishing window configuration
mutation UpdateProductGroupState($input: UpdateProductGroupsStateMutationInput!) {
catalog {
productGroup {
updateState(input: $input) {
updatedCount
productGroupIds
}
}
}
}
{
"input": {
"productGroupIds": [
"product-group-id-1",
"product-group-id-2"
],
"state": "ACTIVE"
}
}

If you use MCP, these tools are relevant:

See Tools for setup and full coverage.

  • A product group belongs to a Workspace
  • A product group has many Products
  • Product groups work alongside Pricing to control what can be sold and when