---
title: "Create a package"
method: POST
path: "/shop/packages"
tags: ["Packages"]
---

# Create a package

`POST /shop/packages`

Creates a new `Package` at the given site. The minimum body is
`name` + `site_id`; everything else has sensible defaults.
Requires the `SETTINGS_MANAGE` permission on `site_id`.

Server-side behaviour worth noting:
- `separate_couples_package_choices` is forced to `false` unless
  both `min_guests` and `max_guests` equal `2`.
- `permitted_membership_type_ids` is filtered to membership types
  within the site's brand; others are silently dropped.
- When `overnight_package_config.enabled=true`, both `rate_id` and
  `num_nights` are required — otherwise the request fails with 422.
- `organisation_id` defaults to the caller's primary organisation
  when omitted.

## Request body

- object
  - `name` string, required — Display name for the package. Visible to customers in the shopfront and to staff in the admin UI. Plain text only.
  - `description` string — Long-form description shown to customers when they're browsing the package. Markdown is rendered.
  - `product_code` string, nullable — Optional product code used to map this package to an external POS or PMS catalog. Free-form string; uniqueness is not enforced server-side.
  - `external_id` string, nullable — External identifier used by integrations to reference this offering. Free-form.
  - `currency` string — The ISO-4217 currency code.
  - `standard_price` integer, nullable — The standard price for this package, in the smallest currency unit (e.g. pence). Optional at create time — packages can be created without a standard price and have one configured later.
  - `site_id` string, required — ID of the site to offer this package at. The caller's API key must have access to the site; requests for a site they don't own get 422.
  - `organisation_id` string, uuid — Optional organisation to attribute this offering to. Defaults to the caller's primary organisation if omitted.
  - `availability_rules` AvailabilityRule[] — Per-day availability rules controlling when this package can be booked. See `AvailabilityRule` for shape.
    - `id` string, object-id, required — The ID of the availability rule.
    - `date_from` string, date, required — The start of the rule period.
    - `date_to` string, date, required — The end of the rule period.
    - `is_available` boolean, required — Whether the resource is available during this period. Any `false` rules will override `true` rules.
    - `max_duration` integer — Maximum number of minutes.
    - `min_duration` integer — Minimum number of minutes.
    - `time_from` string, required — The daily start time of the time period, in 24 hour format.
    - `time_to` string, required — The daily end time of the time period, in 24 hour format.
    - `weekdays` string[] — The weekdays this rule applies to.
  - `offered_online` boolean — When true, the package is bookable via the public shopfront. When false, it's bookable only via the admin UI. Defaults to false.
  - `private` boolean — When true, only customers with the direct link can book this package — it's hidden from category pages and search engines.
  - `visibility` 'public' | 'link_only' | 'private' — Visibility override controlling who can see this package on the shopfront. `public` shows it everywhere; `link_only` keeps it out of browse/search (still bookable by direct link); `private` restricts it to admin booking flows.
  - `customers_only` boolean — When true, only registered customers (not guests) can book this package.
  - `members_only` boolean — When true, only members of permitted membership types can book this package.
  - `permitted_membership_type_ids` string[], nullable — Membership type IDs whose members are allowed to book this package. Only relevant when `members_only=true`. Membership types from outside the site's brand are silently filtered out.
  - `membership_booking_windows_enabled` boolean — When true, members can book this package further in advance than the standard window. The exact extra advance per membership type is defined in `membership_booking_windows`.
  - `membership_booking_windows` MembershipBookingWindow[] — Per-membership-type advance-booking-window overrides.
    - `membership_type_id` string, uuid, required — The ID of the membership type this booking window applies to.
    - `max_advance_bookings_interval` string, required — The maximum time before a booking's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `min_advance_bookings_interval` string, required — The minimum time before a booking's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
  - `item_choices` object[] — The choices customers make when booking this package (e.g. "pick a massage", "pick a lunch course"). Each choice has an allocation, options, start-time rules, and visibility flags. The detailed shape is documented as `PackageItemChoice` under the `Package` schema — the create endpoint accepts the same object shape.
  - `upsell_offerings` OfferingIdentifier[] — Other offerings to upsell on the booking confirmation page.
    - `offering_id` string, mongo-id, required — The ID of the offering.
    - `offering_name` string, required — The name of the offering.
    - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
  - `cross_sell_offerings` OfferingIdentifier[] — Other offerings to cross-sell during the booking flow.
    - `offering_id` string, mongo-id, required — The ID of the offering.
    - `offering_name` string, required — The name of the offering.
    - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
  - `related_retail_offerings` OfferingIdentifier[] — Retail products to display as related to this package on its shopfront page.
    - `offering_id` string, mongo-id, required — The ID of the offering.
    - `offering_name` string, required — The name of the offering.
    - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
  - `category_ids` string[] — Category IDs the package belongs to. Used for shopfront grouping.
  - `meta` object — SEO metadata for the public shopfront page.
    - `title` string, nullable — SEO `<title>`. Falls back to the package name when omitted.
    - `description` string, nullable — SEO meta description. Falls back to the package description when omitted.
  - `customer_cancellation_permitted` 'allowed' | 'if_unpaid' | 'disallowed', nullable — Whether and when customers can cancel a booking of this package themselves. `allowed` = always; `if_unpaid` = only if no payment has been taken; `disallowed` = never (admin only).
  - `customer_cancellation_min_duration` string, nullable — ISO 8601 duration before the package's start during which cancellation is no longer permitted. e.g. `PT24H` = no cancellation in the last 24 hours.
  - `customer_reschedule_permitted` 'allowed' | 'disallowed' | 'unpaid', nullable — Whether and when customers can reschedule a booking of this type themselves. `allowed` = always. `unpaid` = only if no payment has been taken against the order. `disallowed` = never (admin only).
  - `customer_reschedule_min_duration` string, nullable — ISO 8601 duration before the package's start during which rescheduling is no longer permitted. e.g. `PT24H` = no rescheduling in the last 24 hours.
  - `max_daily_duration` integer, nullable — Maximum minutes between the start of the first and end of the last item on each day of the package. Use this to cap how spread-out a single-day package can become.
  - `max_advance_bookings_interval` string, nullable — ISO 8601 duration limiting how far in advance customers can book this package. e.g. `P2W` = up to two weeks ahead.
  - `min_advance_bookings_interval` string, nullable — ISO 8601 duration limiting how soon before the package start a customer can book. e.g. `P2D` = at least two days' notice.
  - `min_guests` integer, nullable — Minimum number of guests for a single booking of this package.
  - `max_guests` integer, nullable — Maximum number of guests for a single booking. Must be `>= min_guests`. Server-side, `separate_couples_package_choices` is forced to `false` unless both `min_guests` and `max_guests` equal `2`.
  - `prevent_choice_overlaps` boolean, nullable — Whether to prevent booking choices in this package from overlapping times.
  - `separate_couples_package_choices` boolean, nullable — For couples packages (both `min_guests` and `max_guests` equal `2`), whether each guest can independently pick choices. Forced to `false` for any other guest configuration.
  - `email_options` object — Email-rendering options for this package.
    - `hide_prices` boolean — When true, prices are hidden from customer emails for cases where the customer didn't pay directly (e.g. corporate or comped bookings).
  - `overnight_package_config` object — Configuration for overnight packages — packages that include a hotel room reservation alongside their other items. When `enabled=true`, both `rate_id` and `num_nights` are required.
    - `enabled` boolean — Whether this package is an overnight package.
    - `rate_id` string, nullable — ID of the PMS rate code the overnight package books against. Required when `enabled=true`.
    - `num_nights` integer, nullable — Number of nights the package books. Required when `enabled=true`.
  - `include_pricing_on_calendar` boolean — Whether to surface the price alongside this package in calendar views.
  - `max_per_basket` integer, nullable — Maximum bookings of this package per basket.
  - `max_per_guest` integer, nullable — Maximum bookings of this package per individual guest within a basket.

## Response `201`

A single `Package`.

- object — Single-item envelope mixin. `allOf` this into any show response that wraps its `data` payload in an outer object; the concrete schema (e.g. `ShowUser`) adds its own `data` property with the appropriate `$ref` and keeps its own title so the SDK surface is unchanged.
  - `data` SchemasPackage, required — A bundled set of offerings sold as a single product (e.g. a "Spa Day" combining treatments, lunch and pool access). Packages declare their allocations — which offering types they include and in what quantities — and how the inner items are scheduled, priced and discounted at checkout.
    - `id` string, required — The ID of the package.
    - `allocations` object, required
    - `categories` SchemasCategory2[], required — The category associated with this package type
      - `id` string, object-id, required — The ID of the category.
      - `name` string, required — The name of the category.
    - `category_ids` string[], required — The category IDs associated with this package type
    - `cross_sell_offerings` OfferingIdentifier[], required
      - `offering_id` string, mongo-id, required — The ID of the offering.
      - `offering_name` string, required — The name of the offering.
      - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
    - `currency` string, required — The ISO-4217 currency code in lower case
    - `customer_cancellation_min_duration` string, nullable, required — The minimum duration that must be left before the booking in order for the customer to cancel, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `customer_cancellation_permitted` 'allowed' | 'disallowed' | 'unpaid', required
    - `customer_reschedule_min_duration` string, nullable, required — The minimum duration that must be left before the booking in order for the customer to reschedule, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `customer_reschedule_permitted` 'allowed' | 'disallowed' | 'unpaid', nullable, required — Whether and when customers can reschedule a booking of this type themselves. `allowed` = always. `unpaid` = only if no payment has been taken against the order. `disallowed` = never (admin only).
    - `customers_only` boolean, required
    - `default_revenue_centre` string, nullable, required — The default revenue centre to fall back to to balance allocations
    - `description` string, required — A description of the package
    - `email_options` PackageOfferingEmailOptions, required
      - `hide_prices` boolean, required — Enable to hide prices from customer emails, in cases where the customer didn't purchase the item directly.
    - `external_id` string, nullable, required — An external identifier for this offering.
    - `image` Media
      - `id` string, uuid, required — Unique identifier of the uploaded media item, returned from `createMedia`. Pass this ID into any field that accepts a media reference (logos, hero images, product images, etc.).
      - `file_name` string, required — Original filename of the uploaded asset, preserved as provided at upload time. Used for display in the media library and as a hint when serving downloads.
      - `mime_type` string, required — The mime type of the media item.
      - `original_url` string, required — The url of the media resource.
      - `size` integer, required — The size of the media item in bytes.
      - `url` string, required — The url of the converted media resource.
    - `include_pricing_on_calendar` boolean, required — Whether the booking engine calendar should display pricing under each date
    - `item_choices` PackageItemChoice[], required — An array of choices for items which may be included in this package.
      - `id` string, required — The ID of this choice.
      - `allocation` object, required
        - `amount` integer, required
        - `revenue_centre` string, required
      - `allow_overlaps` boolean, required — Allow this choice to overlap with other items when `prevent_choice_overlaps` is enabled on the package.
      - `auto_select_timeslot` boolean, required — Whether a timeslot should be automatically selected for this choice
      - `choice_configuration` object, required — Any additional configuration for this choice.
      - `description` string, required — A description of this choice.
      - `hide_times` boolean, required — Whether to hide times for this choice from customers
      - `name` string, required — A name for this choice.
      - `max_options` integer, nullable, required — The maximum number of options that may be chosen.
      - `min_options` integer, nullable, required — The minimum number of options that must be chosen.
      - `offering_type` 'appointment' | 'product' | 'session', required — The type of offerings included in this choice.
      - `option_budget` integer, required — The budget that this package allows for options in this choice. Each option will use its standalone price, and the overall package price will be increased if the total exceeds the budget.
      - `optional` boolean, required — Whether this item choice should be optional.
      - `options` PackageItemChoiceOption[], required — An array of options to make up this choice.
        - `id` string, required — Identifier of the offering this option points at — an `AppointmentType`, `SessionType` or retail `Product`, depending on `item_type`. The guest sees the offering's name and image when picking this option in the storefront.
        - `item_type` string, required — The type of item this option represents.
        - `offering` PackageShopOffering, required
          - `id` string, required — The ID of the offering
          - `categories` object[]
            - `id` string, required — The ID of the category
            - `name` string, required — The name of the category
          - `currency` string, required — The currency code for the price
          - `description` string, required — The name of the offering
          - `discounted_price_from` integer — If set, a discounted 'price from' that applies to the current customer
          - `duration` integer — The duration of the offering in minutes
          - `durations` integer[]
          - `external_id` string, nullable, required — An external identifier for this offering.
          - `has_availability` boolean — Whether there is availability for the offering on the requested date.
          - `image` Media
            - `id` string, uuid, required — Unique identifier of the uploaded media item, returned from `createMedia`. Pass this ID into any field that accepts a media reference (logos, hero images, product images, etc.).
            - `file_name` string, required — Original filename of the uploaded asset, preserved as provided at upload time. Used for display in the media library and as a hint when serving downloads.
            - `mime_type` string, required — The mime type of the media item.
            - `original_url` string, required — The url of the media resource.
            - `size` integer, required — The size of the media item in bytes.
            - `url` string, required — The url of the converted media resource.
          - `max_guests` integer — The maximum guests this offering is for
          - `min_guests` integer — The minimum guests this offering is for
          - `name` string, required — The name of the offering
          - `next_available_date` string, date — The next available date if there is no availability on the given date
          - `price_from` integer — The minimum price of the offering on the given date
          - `price_to` integer — The maximum price of the offering on the given date
          - `type` string — Identifies the type of this model
        - `price_change` integer, nullable, required — A currency amount that this option would increase the package price by.
      - `start_time_rules` PackageChoiceStartTimeRule[], required — An array of rules determining the start times that should be allowed for this choice.
        - `absolute_time_from` string, nullable, required — The earliest allowed start time.
        - `absolute_time_to` string, nullable, required — The latest allowed start time.
        - `relative_mins_from` integer, nullable, required — The minimum number of minutes from the relative base point that should be allowed.
        - `relative_mins_to` integer, nullable, required — The maximum number of minutes from the relative base point that should be allowed.
        - `relative_to` 'first_item_start', nullable, required — The base time that a relative start time should be calculated from.
        - `type` 'relative' | 'absolute', required — The type of the rule.
      - `visible` boolean, required — Whether this item choice should be visible to the customer.
    - `max_advance_bookings_interval` string, nullable, required — The maximum time before the package's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `max_daily_duration` integer, nullable, required — The maximum amount of time between the start of the first and end of the last item on each day of a package, in minutes.
    - `max_guests` integer, required — The maximum guests this package is for
    - `max_per_basket` integer, nullable, required — The maximum number of bookings that may be made in a single basket for this package.
    - `max_per_guest` integer, nullable, required — The maximum number of bookings that may be made by a single guest for this package.
    - `members_only` boolean, required — Whether this package requires an active membership in order to book.
    - `membership_booking_windows` MembershipBookingWindow[], required
      - `membership_type_id` string, uuid, required — The ID of the membership type this booking window applies to.
      - `max_advance_bookings_interval` string, required — The maximum time before a booking's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
      - `min_advance_bookings_interval` string, required — The minimum time before a booking's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `membership_booking_windows_enabled` boolean, required — Whether membership-specific booking windows should be enabled for this package.
    - `meta` object, required
      - `description` string, nullable, required — The meta description of this offering. If not specified, it falls back to the description of the offering.
      - `title` string, nullable, required — The meta title of this offering. If not specified, it falls back to the name of the offering.
    - `min_advance_bookings_interval` string, nullable, required — The minimum time before the package's start time that it may be booked, as an ISO8601 string. See https://en.wikipedia.org/wiki/ISO_8601#Durations
    - `min_guests` integer, required — The minimum guests this package is for
    - `name` string, required — The name of this package
    - `offered_online` boolean, required — Whether this session type is bookable online
    - `overnight_package_config` object, required
      - `enabled` boolean — Whether this package is an overnight package.
      - `rate_id` string — The ID of the rate this package is associated with.
      - `num_nights` integer — The number of nights this package is associated with.
    - `permitted_membership_type_ids` string[] — If this package is for members only, this property may be used to restrict the offering further so it may only be purchased by active members with of one of the given membership types.
    - `prevent_choice_overlaps` boolean, required — Whether to prevent booking choices in this package from overlapping times.
    - `price_rules` PackagePriceRule[], required — The rules defining prices for this package
      - `id` string, required — The ID of the price rule.
      - `package_id` string, required — The ID of the package the price rule relates to.
      - `date_from` string, date, nullable, required — The rule should apply to packages starting on or after this date.
      - `date_to` string, date, nullable, required — The rule should not apply to packages starting after this date.
      - `time_from` string, nullable, required — The rule will apply to packages that have bookings starting on or after this time.
      - `time_to` string, nullable, required — The rule will apply to packages that have bookings starting before this time.
      - `weekdays` string[], required — The rule should apply to packages starting on any of these weekdays.
      - `price` integer, required — The price of the package.
    - `private` boolean, required — Whether this is private. When private, it is accessible from the URL but doesn't appear on category pages and isn't indexed on search engines.
    - `product_code` string, nullable, required — A custom product code for the package.
    - `related_retail_offerings` OfferingIdentifier[], required
      - `offering_id` string, mongo-id, required — The ID of the offering.
      - `offering_name` string, required — The name of the offering.
      - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
    - `separate_couples_package_choices` boolean, required — If this is a couples package, defines whether each person should be able to make different choices.
    - `site_id` string, required — The ID of the site the package belongs to.
    - `standard_price` integer, nullable, required — The standard price for this package, in the smallest currency unit (e.g. pence). `null` if a standard price hasn't been configured — this is distinct from a price of zero.
    - `upsell_offerings` OfferingIdentifier[], required
      - `offering_id` string, mongo-id, required — The ID of the offering.
      - `offering_name` string, required — The name of the offering.
      - `offering_type` 'appointment' | 'appointment_enquiry' | 'area_booking' | 'course' | 'hotel_room_reservation' | 'membership' | 'package' | 'product' | 'session' | 'table_reservation' | 'voucher', required — Discriminator describing what kind of sellable item an `Offering` represents. The value determines which downstream schema (`Appointment`, `Session`, `Package`, etc.) the offering's `offering_id` resolves against, and which checkout/booking flow applies.
    - `visibility` 'public' | 'link_only' | 'private' — The visibility status of the product.
    - `deleted_at` string, date-time, nullable, required — When then resource was deleted.
    - `updated_at` string, date-time, required — When then resource was last updated.

## Other responses

- `401` — The user is unauthenticated
- `403` — The authenticated user does not have permission.
- `422` — The request didn't pass validation

---

[API](https://skmtc.dev/try/apis/trybe-api.md) · [All operations](https://skmtc.dev/try/apis/trybe-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/try/trybe-api/revisions/f37f92702da5/schema)
