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.
Key Concepts
Section titled “Key Concepts”Contract windows
Section titled “Contract windows”Each product group has contract date boundaries:
contractEarliestStartDatecontractLatestStartDatecontractEarliestEndDatecontractLatestEndDate
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
contractEarliestStartDateandcontractLatestStartDate(e.g. a student arriving late). - A booking can end anywhere between
contractEarliestEndDateandcontractLatestEndDate(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].
State and publishing
Section titled “State and publishing”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 segments
Section titled “Product segments”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.
Product membership
Section titled “Product membership”A product group contains a connection of products. This lets you inspect the products that belong to the group and paginate through them.
GraphQL API
Section titled “GraphQL API”ProductGroup
Section titled “ProductGroup”| 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 |
CatalogProductGroupStateEnum
Section titled “CatalogProductGroupStateEnum”| Value | Description |
|---|---|
ACTIVE |
Product group is active |
INACTIVE |
Product group is inactive |
CatalogProductSegmentEnum
Section titled “CatalogProductSegmentEnum”| 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 |
CatalogPublishStateEnum
Section titled “CatalogPublishStateEnum”| Value | Description |
|---|---|
SCHEDULED |
Publishing has not started yet |
ONGOING |
Publishing is currently active |
FINISHED |
Publishing window has ended |
Queries
Section titled “Queries”Get a product group
Section titled “Get a product group”query ProductGroup($id: ID!) { catalog { productGroup(id: $id) { id internalReference state productSegment publishing { startDate endDate state } products { totalCount } } }}{ "id": "product-group-id"}List product groups
Section titled “List product groups”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:
productGroupsfollows the standard connection pattern. Use cursors for pagination when iterating through large catalogs.
Mutations
Section titled “Mutations”Create a product group
Section titled “Create a product group”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 |
Update a product group
Section titled “Update a product group”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 |
Update product group state in bulk
Section titled “Update product group state in bulk”mutation UpdateProductGroupState($input: UpdateProductGroupsStateMutationInput!) { catalog { productGroup { updateState(input: $input) { updatedCount productGroupIds } } }}{ "input": { "productGroupIds": [ "product-group-id-1", "product-group-id-2" ], "state": "ACTIVE" }}MCP Tools
Section titled “MCP Tools”If you use MCP, these tools are relevant:
See Tools for setup and full coverage.