SubblySubbly
Log inGet started
  • Get started
  • Developer resources
Private API reference
Docs
Information
    Base URLAuthenticationPaginationErrors
Customer
    Get list of customersCreate a customerGet customer by IDUpdate a customerDelete a customerChange a customer's store credit balanceCreate a customer noteUpdate a customer noteDelete a customer note
Address
    Create an addressUpdate an addressDelete an address
Pickup Info
    Get list of pickup infoCreate pickup infoUpdate pickup infoDelete pickup info
Subscription
    Get list of subscriptionsCreate a subscriptionGet subscription by IDUpdate a subscriptionCancel a subscriptionUndo cancellationPause a subscriptionResume a subscriptionSkip renewals until a dateReactivate a cancelled or expired subscriptionSwitch the subscription to another plan by starting overChange the plans of the subscription's itemsUpdate a subscription's shipping address and methodUpdate a subscription's payment methodUpdate a subscription's survey preferencesCreate a subscription itemShow a subscription itemUpdate a subscription itemRemove a subscription itemUpdate a subscription item's preferencesUpdate a subscription item's bundleChange the plan of a subscription itemChange the variant of a one-time itemApply a discount to a subscription itemRemove a subscription item discountApply a discount to a subscriptionRemove a subscription discount
Invoice
    Get list of invoicesGet invoice by IDSchedule the next payment for invoiceVoid an invoiceForgive an invoiceMark an invoice as paid
Order
    Get list of ordersGet order by IDUpdate an orderShip an orderCancel an orderMark an order as pendingArchive an orderMark an order as a future shipmentSync order shipping items
Payment Method
    Create a payment methodGet payment method by IDDelete a payment method
Transaction
    Get list of transactionsGet transaction by ID
Cancellation
    Get shop cancellation reasons
Product
    Get list of productsGet product by IDGet variant by IDUpdate variantGet plan by IDUpdate planCreate subscription productUpdate subscription productPublish subscription productUnpublish subscription productArchive subscription productSync subscription product metadataCreate one-time productUpdate one-time productPublish one-time productUnpublish one-time productArchive one-time productSync one-time product metadataCreate variantArchive variantBatch create/update/archive variantsCreate planArchive plan
Survey
    Get survey by IDGet list of surveys
Bundle
    Get list of bundlesCreate a new bundleGet bundle by IDUpdate a bundleGet list of bundle itemsCreate a bundle itemBatch create bundle itemsGet bundle item by IDUpdate a bundle itemDelete a bundle itemGet list of bundle groupsPublish a bundleUnpublish a bundleArchive a bundleSync bundle metadataCreate a bundle planGet bundle plan by IDUpdate a bundle planArchive a bundle plan
Tag
    Get list of tags
Metafield
    Get shop's metafieldsCreate a new metadataUpdate the metadata
Funnel
    Get list of funnelsGet funnel by ID
Option
    Get list of options
Country
    Get list of countries
Inventory
    Get list of inventory itemsCreate a new inventory itemGet inventory item by IDUpdate an inventory itemArchive an inventory itemGet list of inventory groupsCreate a new inventory groupGet inventory group by IDUpdate an inventory group
Coupon
    Get list of couponsCreate a couponGet coupon by IDUpdate a couponArchive a coupon
Product Collection
    Get list of product collectionsCreate a product collectionGet product collection by IDUpdate a product collectionPublish a product collectionUnpublish a product collectionArchive a product collectionGet list of collection groups with itemsSync collection items

Bundle

Private Bundle API endpoints

Endpoints
  • GET/bundles
  • POST/bundles
  • GET/bundles/{bundle_id}
  • PUT/bundles/{bundle_id}
  • GET/bundles/{bundle_id}/items
  • POST/bundles/{bundle_id}/items
  • POST/bundles/{bundle_id}/items/batch
  • GET/bundles/{bundle_id}/items/{item_id}
  • PUT/bundles/{bundle_id}/items/{item_id}
  • DELETE/bundles/{bundle_id}/items/{item_id}
  • GET/bundles/{bundle_id}/groups
  • POST/bundles/{bundle_id}/publish
  • POST/bundles/{bundle_id}/unpublish
  • POST/bundles/{bundle_id}/archive
  • POST/bundles/{bundle_id}/metadata
  • POST/bundles/{bundle_id}/plans
  • GET/bundles/{bundle_id}/plans/{plan_id}
  • PUT/bundles/{bundle_id}/plans/{plan_id}
  • POST/bundles/{bundle_id}/plans/{plan_id}/archive

Get list of bundles

GET /bundles

An API endpoint to get list of bundles. The private API can access both published and unpublished bundles. Relation fields are only populated when requested through expand. Accepted values: images, rulesets, plans, preferences, filters, discounts, prices, items_count, tags, metadata. Unrequested relations come back as empty arrays (items_count as 0, metadata as null); tags and tags_meta are both driven by expand=tags. Unknown names are ignored.

Query parameters

pageoptionalinteger

Page number for pagination

per_pageoptionalinteger

Items per page

Defaults to 10.

ids[]optionalinteger[]

Filter by bundle IDs. Values must be unique.

slugs[]optionalstring[]

Filter by bundle slugs. Values must be unique.

tags[]optionalstring[]

Filter by tags. Values must be unique.

publishedoptionalboolean

Filter by published status

configurableoptionalboolean

Filter by configurable bundles

digitaloptionalboolean

Filter by digital bundles

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

sort[field]optionalstring

Field to sort by. Required whenever any sort[...] parameter is sent, so sort[direction] on its own is rejected.

Possible values: id, name.

sort[direction]optionalstring

Sort direction; defaults to asc.

Possible values: asc, desc.

Defaults to "asc".

Returnsobject

Bundles list response

Error responses

422object

A query parameter is invalid. ids, tags and slugs must be arrays without duplicates, ids entries must be integers, slugs entries at most 80 characters and tags entries at most 255 characters. sort.field must be id or name and sort.direction asc or desc. published, configurable and digital must be booleans, page at least 1, per_page between 1 and 100, and expand an array.

curl https://api.subbly.co/private/v1/bundles \ -H 'X-API-KEY: <api-key>'
Response
{ "pagination": { "current_page": 1, "last_page": 2, "from": 1, "to": 1, "total": 20 }, "data": [ { "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ] }

Create a new bundle

POST /bundles

This operation accepts no expand parameter, so the relation fields of the returned bundle are always empty. Read the bundle back with expand to see them.

Request body

configurableRequiredinteger

Possible values: 0, 1.

selection_typeoptionalstring | null

Required when configurable=1. When configurable=0 any value sent is ignored and stored as null.

Possible values: variant, product, single_product.

digitaloptionalinteger

Possible values: 0, 1.

slugRequiredstring

Must be unique among the shop's bundles.

nameoptionalstring | null
hidden_itemsoptionalinteger

Possible values: 0, 1.

searchableoptionalinteger

Possible values: 0, 1.

show_ruleset_nameoptionalinteger

Possible values: 0, 1.

descriptionoptionalstring | null
delivery_infooptionalstring | null
setup_feeoptionalinteger | null
pre_order_end_atoptionalstring | null

Date in Y-m-d format. Must be today or later; past dates are rejected.

Format: date.

gifting_enabledoptionalinteger

Prohibited when digital=1.

Possible values: 0, 1.

pause_enabledoptionalinteger

0 is only accepted on plans with the optional-pause feature; other shops must send 1.

Possible values: 0, 1.

price_typeoptionalstring | null

Only accepted for configurable bundles; rejected when selection_type is single_product, when ruleset_type is total, or when discount_type is also non-null.

Possible values: total, per_item.

discount_typeoptionalstring | null

Only accepted for configurable bundles; rejected when price_type is also non-null (except for single_product bundles).

Possible values: per_item, total, percentage.

ruleset_typeoptionalstring

Omit the field to leave it unset; sending an explicit null is rejected. Only accepted for configurable bundles whose selection_type is not single_product.

Possible values: quantity, total.

appearance_typeoptionalstring

Omit the field to leave it unset; sending an explicit null is rejected. Only accepted for configurable bundles whose selection_type is not single_product.

Possible values: one_step, two_step, without_ruleset.

quantity_selectorsoptionalinteger[] | null

Only accepted for configurable bundles whose selection_type is variant or product; prohibited otherwise. Must be a JSON list, not an object.

collect_shipping_addressoptionalinteger | null

Must be 1 unless the bundle is digital; 0 is only accepted when digital=1.

Possible values: 0, 1.

funnel_idoptionalinteger | null
tagsoptionalobject
filtersoptionalobject

Only accepted for configurable bundles whose selection_type is variant or product; prohibited otherwise.

preferencesoptionalobject

Only accepted for configurable bundles whose selection_type is variant or product; prohibited otherwise.

rulesetsoptionalobject

Only accepted for configurable bundles whose selection_type is variant or product; prohibited otherwise.

imagesoptionalobject

ReturnsBundle

Bundle created successfully

Error responses

422object

The body fails validation. This happens, for example, when configurable or slug is missing, when slug is longer than 70 characters or another bundle of the shop already uses it, when a configurable bundle has no selection_type, or when funnel_id is not a funnel of the shop. Bundle options that do not fit the bundle kind also fail: price_type, discount_type, ruleset_type or appearance_type on a bundle that does not support them (for example Price type is only available for configurable bundles.), quantity_selectors, filters, preferences or rulesets on a bundle that is not configurable or is single product, gifting_enabled on a digital bundle, or collect_shipping_address set to 0 on a physical bundle. Other causes: pause_enabled is 0 but the shop plan has no optional pause (Pause is not available on your current plan.), a filter or preference attribute is not a preset single line attribute of the shop (for example Only preset attributes can be used for filters and preferences.), ruleset ranges overlap (Ruleset quantity ranges must not overlap.) or total ranges have gaps, or there are more than 5 images.

curl -X POST https://api.subbly.co/private/v1/bundles \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "configurable": 0, "selection_type": "variant", "digital": 0, "slug": "slug", "name": "name", "hidden_items": 0, "searchable": 0, "show_ruleset_name": 0, "description": "description", "delivery_info": "delivery_info", "setup_fee": 0, "pre_order_end_at": "2026-01-15", "gifting_enabled": 0, "pause_enabled": 0, "price_type": "total", "discount_type": "per_item", "ruleset_type": "quantity", "appearance_type": "one_step", "quantity_selectors": [ 1 ], "collect_shipping_address": 0, "funnel_id": 1, "tags": { "create": [ { "value": "value" } ] }, "filters": { "create": [ { "metadata_id": 1 } ] }, "preferences": { "create": [ { "attribute_id": 1, "title": "title" } ] }, "rulesets": { "create": [ { "min": 0, "max": 1, "name": "name", "cta_text": "cta_text" } ] }, "images": { "create": [ { "url": "url", "order": 0 } ] } }'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Get bundle by ID

GET /bundles/{bundle_id}

A detailed description of the bundle. The private API can access both published and unpublished bundles. Relation fields are only populated when requested through expand. Accepted values: images, rulesets, plans, preferences, filters, discounts, prices, items_count, tags, metadata. Unrequested relations come back as empty arrays (items_count as 0, metadata as null); tags and tags_meta are both driven by expand=tags. Unknown names are ignored.

Path parameters

bundle_idRequiredinteger

Bundle ID

Query parameters

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

expand is sent but is not an array.

curl https://api.subbly.co/private/v1/bundles/{bundle_id} \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Update a bundle

PUT /bundles/{bundle_id}

This operation accepts no expand parameter, so the relation fields of the returned bundle are always empty. Read the bundle back with expand to see them.

Path parameters

bundle_idRequiredinteger

Bundle ID

Request body

slugoptionalstring

Must be unique among the shop's bundles.

nameoptionalstring
hidden_itemsoptionalinteger

Possible values: 0, 1.

searchableoptionalinteger

Possible values: 0, 1.

show_ruleset_nameoptionalinteger

Prohibited unless the bundle is configurable.

Possible values: 0, 1.

descriptionoptionalstring | null
delivery_infooptionalstring | null
setup_feeoptionalinteger | null
pre_order_end_atoptionalstring | null

Date in Y-m-d format. Must be today or later; past dates are rejected.

Format: date.

gifting_enabledoptionalinteger

Prohibited when the bundle is digital.

Possible values: 0, 1.

pause_enabledoptionalinteger

0 is only accepted on plans with the optional-pause feature; other shops must send 1.

Possible values: 0, 1.

price_typeoptionalstring | null

Must be present in the payload whenever discount_type or ruleset_type is sent (send null if not applicable). Only accepted for configurable bundles; rejected when selection_type is single_product, when ruleset_type is total, or when discount_type is also non-null.

Possible values: total, per_item.

discount_typeoptionalstring | null

Must be present in the payload whenever price_type is sent (send null if not applicable). Only accepted for configurable bundles; rejected when price_type is also non-null (except for single_product bundles).

Possible values: per_item, total, percentage.

ruleset_typeoptionalstring

Only accepted for configurable bundles whose selection_type is not single_product. Rejected while the bundle has active subscriptions.

Possible values: quantity, total.

appearance_typeoptionalstring

Only accepted for configurable bundles whose selection_type is not single_product.

Possible values: one_step, two_step, without_ruleset.

quantity_selectorsoptionalinteger[] | null

Only accepted when the bundle is configurable and its selection_type is not single_product. Must be a JSON list, not an object.

collect_shipping_addressoptionalinteger

Must be 1 unless the bundle is digital; 0 is only accepted for digital bundles.

Possible values: 0, 1.

funnel_idoptionalinteger | null
change_product_collection_idoptionalinteger | null

ID of the product collection used for cross-product plan switching. Must be a non-archived collection of the shop whose type is 'subscription' or unset.

tagsoptionalobject
filtersoptionalobject

Only accepted when the bundle is configurable and its selection_type is not single_product.

preferencesoptionalobject

Only accepted when the bundle is configurable and its selection_type is not single_product.

rulesetsoptionalobject

Prohibited when the bundle is not configurable or its selection_type is single_product, and prohibited in the same request as ruleset_type; change the ruleset type in a separate call. After create, update and delete are applied the resulting set must hold at least one ruleset and must satisfy the range rules for the bundle's ruleset_type.

imagesoptionalobject

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

The body fails validation. This happens, for example, when slug is longer than 70 characters or another bundle of the shop already uses it, when ruleset_type is sent while the bundle has active subscribers (Cannot change ruleset type while there are active subscribers.), or when discount_type or ruleset_type is sent without price_type (Price type must be present when updating discount type or ruleset type. Set to null if not applicable.). Ruleset changes fail when rulesets is sent together with ruleset_type, when no active ruleset would remain (At least one active ruleset must remain.), when ranges overlap, or when a ruleset to delete has active subscriptions (Cannot delete a ruleset that has active subscriptions.). Other causes: a second filter (Only one filter is allowed per bundle. Delete the existing filter before creating a new one.), more than 5 images in total (A bundle cannot have more than 5 images.), pause_enabled set to 0 without the plan feature, options that do not fit the bundle kind, and IDs in preferences, rulesets, images, tags, funnel_id or change_product_collection_id that do not belong to this bundle or shop.

curl -X PUT https://api.subbly.co/private/v1/bundles/{bundle_id} \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "slug": "slug", "name": "name", "hidden_items": 0, "searchable": 0, "show_ruleset_name": 0, "description": "description", "delivery_info": "delivery_info", "setup_fee": 0, "pre_order_end_at": "2026-01-15", "gifting_enabled": 0, "pause_enabled": 0, "price_type": "total", "discount_type": "per_item", "ruleset_type": "quantity", "appearance_type": "one_step", "quantity_selectors": [ 1 ], "collect_shipping_address": 0, "funnel_id": 1, "change_product_collection_id": 1, "tags": { "create": [ { "value": "value" } ], "delete": [ { "id": 1 } ] }, "filters": { "create": [ { "metadata_id": 1 } ], "delete": [ { "metadata_id": 1 } ] }, "preferences": { "create": [ { "attribute_id": 1, "title": "title" } ], "update": [ { "id": 1, "title": "title" } ], "delete": [ { "id": 1 } ] }, "rulesets": { "create": [ { "min": 0, "max": 1, "name": "name", "cta_text": "cta_text" } ], "update": [ { "id": 1, "min": 0, "max": 1, "name": "name", "cta_text": "cta_text" } ], "delete": [ { "id": 1 } ] }, "images": { "create": [ { "url": "url", "order": 0 } ], "update": [ { "id": 1, "order": 0 } ], "delete": [ { "id": 1 } ] } }'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Get list of bundle items

GET /bundles/{bundle_id}/items

An API endpoint to get list of items within a bundle.

Path parameters

bundle_idRequiredinteger

Bundle ID

Query parameters

pageoptionalinteger

Page number for pagination

Defaults to 1.

per_pageoptionalinteger

Items per page

Defaults to 10.

filters[]optionalobject[]

Filter by metadata. A list of filter objects. Only preset metadata with single_line_string data type can be used for filtering.

variant_ids[]optionalinteger[]

Filter by variant IDs

queryoptionalstring

Search query for bundle items

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

Returnsobject

Bundle items list response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

A query parameter is invalid. Each filters entry needs an attribute_id (or metafield_id) that is a preset single line attribute of the shop (for example The selected attribute was not found. or Only preset attributes can be used for filters and preferences.) and a values array of existing attribute value IDs. variant_ids must be an array of integers, query at most 50 characters, page at least 1, per_page between 1 and 500, and expand an array.

curl https://api.subbly.co/private/v1/bundles/{bundle_id}/items \ -H 'X-API-KEY: <api-key>'
Response
{ "pagination": { "current_page": 1, "last_page": 2, "from": 1, "to": 1, "total": 20 }, "data": [ { "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ] }

Create a bundle item

POST /bundles/{bundle_id}/items

Path parameters

bundle_idRequiredinteger

Bundle ID

Request body

variant_idRequiredinteger

Product variant ID to add. Must be a non-archived one-time product variant belonging to the shop (not a gift card, not a bundle), and must not already be an item of this bundle.

quantityoptionalinteger | null

Prohibited when the bundle is configurable; sending it returns 422 "Quantity is not available for configurable bundles."

positionoptionalinteger | null
extra_priceoptionalinteger | null

Extra price in cents. Only available for configurable bundles; sending it on a non-configurable bundle returns 422 "Extra price is only available for configurable bundles."

settingsoptionalobject | null

Only available for configurable bundles whose selection type is not "single"; sending it otherwise returns 422.

ReturnsBundleItem

Bundle item created successfully

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

variant_id is missing or cannot be added: The selected variant was not found., Only product variants can be added as bundle item., The selected variant is archived. or This variant is already in this bundle.. The request also fails when quantity is sent for a configurable bundle (Quantity is not available for configurable bundles.), extra_price for a bundle that is not configurable, or settings for a bundle that is not configurable or is single product (Settings are only available for configurable bundles with multiple products.), or when a settings.create entry has a duplicate or non-active bundle_ruleset_id or a max_quantity below 1.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/items \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "variant_id": 1, "quantity": 1, "position": 1, "extra_price": 0, "settings": { "create": [ { "bundle_ruleset_id": 1, "max_quantity": 1 } ] } }'
Response
{ "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Batch create bundle items

POST /bundles/{bundle_id}/items/batch

Path parameters

bundle_idRequiredinteger

Bundle ID

Request body

createRequiredobject[]

Returnsobject

Batch bundle items created successfully

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

create is missing, is not an array, or has more than 200 items. Each create.*.variant_id must be unique in the request and pass the same checks as a single item (The selected variant was not found., Only product variants can be added as bundle item., The selected variant is archived., This variant is already in this bundle.). Per item, quantity is not allowed on a configurable bundle, extra_price only on a configurable bundle, and settings only on a configurable bundle that is not single product (Settings are only available for configurable bundles with a variant or product selection type.). A bundle_ruleset_id must be an active ruleset of the bundle and must not repeat inside one item.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/items/batch \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "create": [ { "variant_id": 1, "quantity": 1, "position": 1, "extra_price": 0, "settings": { "create": [ { "bundle_ruleset_id": 1, "max_quantity": 1 } ] } } ] }'
Response
{ "create": [ { "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ] }

Get bundle item by ID

GET /bundles/{bundle_id}/items/{item_id}

Get a specific bundle item by ID.

Path parameters

bundle_idRequiredinteger

Bundle ID

item_idRequiredinteger

Bundle item ID

Query parameters

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

ReturnsBundleItem

Bundle item object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop, or no item with this ID belongs to the bundle.

422object

expand is sent but is not an array.

curl https://api.subbly.co/private/v1/bundles/{bundle_id}/items/{item_id} \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Update a bundle item

PUT /bundles/{bundle_id}/items/{item_id}

Path parameters

bundle_idRequiredinteger

Bundle ID

item_idRequiredinteger

Bundle item ID

Request body

quantityoptionalinteger | null

Prohibited when the bundle is configurable; sending it returns 422 "Quantity is not available for configurable bundles."

positionoptionalinteger | null
extra_priceoptionalinteger | null

Extra price in cents. Only available for configurable bundles; sending it on a non-configurable bundle returns 422 "Extra price is only available for configurable bundles."

settingsoptionalobject

Only available for configurable bundles whose selection type is not "single"; sending it otherwise returns 422.

ReturnsBundleItem

Bundle item object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop, or no item with this ID belongs to the bundle.

422object

The body fails validation. quantity is not allowed on a configurable bundle (Quantity is not available for configurable bundles.), extra_price only on a configurable bundle (Extra price is only available for configurable bundles.), and settings only on a configurable bundle that is not single product (Settings are only available for configurable bundles with multiple products.). A settings.create entry needs a unique, active bundle_ruleset_id of the bundle, settings.update and settings.delete IDs must be settings of this item, and max_quantity must be at least 1.

curl -X PUT https://api.subbly.co/private/v1/bundles/{bundle_id}/items/{item_id} \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "quantity": 1, "position": 1, "extra_price": 0, "settings": { "create": [ { "bundle_ruleset_id": 1, "max_quantity": 1 } ], "update": [ { "id": 1, "max_quantity": 1 } ], "delete": [ { "id": 1 } ] } }'
Response
{ "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Delete a bundle item

DELETE /bundles/{bundle_id}/items/{item_id}

Deleting is refused with 400 minimum_items_required when the bundle currently has fewer than 2 items. A bundle must keep at least 2 items.

Path parameters

bundle_idRequiredinteger

Bundle ID

item_idRequiredinteger

Bundle item ID

ReturnsBundleItem

Bundle item deleted

Error responses

400any

minimum_items_required. The bundle must keep at least 2 items.

404object

No bundle with this ID exists in the shop, or no item with this ID belongs to the bundle.

curl -X DELETE https://api.subbly.co/private/v1/bundles/{bundle_id}/items/{item_id} \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "product_id": 1, "bundle_id": 1, "product": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant_id": 1, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "settings": [ { "id": 1, "ruleset_id": 1, "max_quantity": 1, "created_at": "2026-01-15T10:30:00Z", "updated_at": "2026-01-15T10:30:00Z" } ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Get list of bundle groups

GET /bundles/{bundle_id}/groups

An API endpoint to get list of groups within a bundle. expand[]: List of relations to expand. items is always present and does not need to be requested. Available keys: product (the parent product of the group). Nested paths are supported, e.g. product.variants. Unknown keys are ignored.

Path parameters

bundle_idRequiredinteger

Bundle ID

Query parameters

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

pageoptionalinteger

Page number for pagination

Defaults to 1.

per_pageoptionalinteger

Items per page

Defaults to 10.

Returnsobject

Bundle groups list response

Error responses

400object

The bundle is archived.

404object

Bundle not found, or it belongs to another shop.

curl https://api.subbly.co/private/v1/bundles/{bundle_id}/groups \ -H 'X-API-KEY: <api-key>'
Response
{ "pagination": { "current_page": 1, "last_page": 2, "from": 1, "to": 1, "total": 20 }, "data": [ { "id": 1, "bundle_id": 1, "name": "Main Items", "description": "Select your main items", "position": 1, "product_id": 10, "product": { "id": 1, "bundle_id": 1, "bundle": {}, "bundle_ruleset_id": 1, "bundle_ruleset": {}, "slug": "yellow-t-shirt-with-pokemon-print", "type": "one_time", "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "delivery_info": "Free shipping on orders over $100", "collect_shipping_address": true, "gifting_enabled": true, "digital": false, "images": [ {} ], "tags": [ "new", "featured" ], "tags_meta": [], "published": true, "metadata": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "min_quantity": 1, "max_quantity": 3, "items": [ { "id": 1, "product_id": 1, "bundle_id": 1, "product": {}, "variant_id": 1, "variant": {}, "settings": [ {} ], "extra_price": 1, "stock_count": 1, "quantity": 1, "position": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ] }

Publish a bundle

POST /bundles/{bundle_id}/publish

Path parameters

bundle_idRequiredinteger

Bundle ID

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is archived, is already published, has no items, or has no active (non-archived) plans.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/publish \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Unpublish a bundle

POST /bundles/{bundle_id}/unpublish

Path parameters

bundle_idRequiredinteger

Bundle ID

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is archived, or is not currently published.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/unpublish \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Archive a bundle

POST /bundles/{bundle_id}/archive

Path parameters

bundle_idRequiredinteger

Bundle ID

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is already archived, or still has active subscriptions.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/archive \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Sync bundle metadata

POST /bundles/{bundle_id}/metadata

Attaches and detaches metadata on the bundle. The bundle must not be archived, otherwise the request returns 400 (entity_archived).

Path parameters

bundle_idRequiredinteger

Bundle ID

Request body

Metadata sync request body

metadataRequiredobject

ReturnsBundle

Bundle object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

metadata is missing or not an object, a metadata.create entry has no name, a name longer than 255 characters, an empty values array, or values of the wrong type for an existing attribute, or a metadata.delete entry names an attribute that is not in the shop (The attribute does not exist.) or lists value IDs that repeat (The value IDs must be unique.) or are not attached to the bundle.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/metadata \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "metadata": { "create": [ { "name": "name", "description": "description", "values": [ "values" ] } ], "delete": [ { "attribute_id": 1, "values": [ 1 ] } ] } }'
Response
{ "id": 1, "name": "Bundle Name", "slug": "Bundle slug", "digital": false, "delivery_info": "delivery_info", "configurable": true, "images": [ { "id": 1, "url": "https://cdn.filestackcontent.com/security=p:<policy>,s:<signature>/resize=w:1000,h:1000,fit:max/output=format:png/quality=v:70/AaBbCcDdEeFf", "order": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "description": "description", "hidden_items": true, "searchable": false, "show_ruleset_name": false, "quantity_selectors": [ 1 ], "selection_type": "variant", "discount_type": "per_item", "price_type": "per_item", "ruleset_type": "total", "appearance_type": "one_step", "rulesets": [ { "id": 1, "name": "Ruleset Name", "min_quantity": 1, "max_quantity": 2, "cta_text": "Add to cart", "products": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "plans": [ { "id": 1, "pricing": {}, "plan": {}, "variant": {}, "pricings": [ {} ], "variants": [ {} ], "prices": [ {} ], "discounts": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "preferences": [ { "id": 1, "title": "Do you want only vageterian dishes?", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "filters": [ { "id": 1, "title": "Type of dish", "attribute_id": 1, "metafield_id": 1, "values": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "tags": [ "new", "bundle" ], "tags_meta": [ { "id": 12, "value": "VIP" } ], "setup_fee": 500, "gifting_enabled": false, "pause_enabled": false, "pre_order_end_at": "2024-12-31", "funnel_id": 1, "change_product_collection_id": 1, "collect_shipping_address": true, "published": true, "items_count": 5, "plans_count": 2, "rulesets_count": 1, "metadata": [ { "id": 1, "name": "Color", "slug": "color-red", "description": "description", "unit": "kg", "data_type": "single_line_string", "preset": true, "multiple": true, "variant": true, "access_level": "storefront", "save_behavior": "customer", "editable": true, "values": [ {} ] } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Create a bundle plan

POST /bundles/{bundle_id}/plans

Path parameters

bundle_idRequiredinteger

Bundle ID

Request body

typeRequiredstring

A bundle may have at most one active one_time plan; creating a second one is rejected. There is no such limit on subscription plans.

Possible values: subscription, one_time.

nameRequiredstring
pricesoptionalobject[]

Required unless the bundle is configurable with no price_type; prohibited when the bundle is configurable and price_type is null. Must contain exactly one entry per active (non-archived) bundle ruleset. Quantities must be unique within a ruleset, the first entry's first range quantity must be 1, and every ruleset must repeat the same set of range quantities.

discountsoptionalobject[]

Only accepted when the bundle is configurable, has no price_type, and has a discount_type; prohibited otherwise. Must contain exactly one entry per active (non-archived) bundle ruleset, with unique quantities per ruleset, a first range quantity of 1, and the same set of range quantities across every ruleset.

frequency_unitoptionalstring

Required for subscription type. day is rejected when a rebilling day is set without an anchor_date (soft-anchored billing).

Possible values: day, week, month.

frequency_countoptionalinteger

Required for subscription type. Minimum is 1, but rises to 2 when rebilling_day is set together with frequency_unit day.

shippingsoptionalobject[]

Required for non-digital subscription bundles. Prohibited for digital bundles. Every entry must use the same shape: all buffered (add_unit/add_count) or all anchored (unit_day/unit_offset).

anchor_dateoptionalstring | null

Date in Y-m-d format; the literal 'today' is accepted and normalised. Only allowed when at least one shippings entry uses unit_day (anchored shipping), and required there when frequency_unit is day. Rejected when frequency_count is 1. For ad-hoc plans (no rebilling day set) it must be today. Otherwise it must fall between tomorrow and now plus frequency_count frequency_units.

Format: date.

rebilling_dayoptionalinteger | null

For daily frequency on non-digital bundles. Must be 1. Mutually exclusive with rebilling_day_of_month and rebilling_day_of_week.

Possible values: 1.

rebilling_day_of_monthoptionalinteger | null

For monthly frequency on non-digital bundles. Day of month (1-31). Mutually exclusive with rebilling_day and rebilling_day_of_week. When anchor_date is set it must equal that date's day of month.

rebilling_day_of_weekoptionalinteger | null

For weekly frequency on non-digital bundles. Day of week (1-7, Monday = 1). Mutually exclusive with rebilling_day and rebilling_day_of_month. When anchor_date is set it must equal that date's ISO day of week.

cut_off_daysoptionalinteger | null

Required when at least one shippings entry uses unit_day (anchored shipping), and prohibited otherwise. A non-zero value must not exceed the number of days in one billing cycle (frequency_unit x frequency_count).

cut_off_timeoptionalstring | null

Time in HH:MM (24h). Defaults to 23:59 when cut_off_days is sent without it. Rejected for digital bundles, for schedules that are not anchored (no unit_day), and when the shop's plan does not include the cut-off time feature.

charge_immediatelyoptionalinteger

Prohibited for digital bundles. Must be sent together with ship_immediately. For ad-hoc plans (no rebilling day set) only 1 is accepted.

Possible values: 0, 1.

ship_immediatelyoptionalinteger

Must be sent together with charge_immediately. Cannot be 1 while charge_immediately is 0.

Possible values: 0, 1.

buffer_daysoptionalinteger | null

Prohibited for digital bundles and rejected unless ship_immediately is 1. Maximum is frequency_count multiplied by 1 for day, 7 for week, or 31 for month frequency.

trial_priceoptionalinteger | null

Prohibited on pre-order bundles and on plans with a rebilling day set (non ad-hoc). Must be sent together with trial_length_days.

trial_length_daysoptionalinteger | null

Prohibited on pre-order bundles and on plans with a rebilling day set (non ad-hoc). Must be sent together with trial_price.

trial_single_orderoptionalinteger

Can only be 1 on non-digital bundles and only when trial_length_days is set.

Possible values: 0, 1.

commitment_billing_countoptionalinteger | null

Only accepted when the shop's plan includes commitment billing; otherwise rejected.

charges_limitoptionalinteger | null
survey_idoptionalinteger | null

ReturnsBundlePlan

Bundle plan created successfully. Only variant, prices and discounts are populated; pricing and plan are always null on this response, so fetch the plan with GET and expand[]=plan to retrieve them.

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop.

422object

The body fails validation. type is missing, is not subscription or one_time, or asks for a second one-time plan (Only one one-time plan is allowed per bundle.), or name is missing. prices is missing when the bundle needs it, is sent when it is not allowed (Prices are not available for configurable bundles without a price type.), or does not have one entry per active ruleset (The prices must include an entry for each active ruleset.). discounts fails the same way (Discounts require a configurable bundle with discount type and no price type.). Subscription plans also fail on a missing or invalid frequency_unit or frequency_count, missing shippings on a physical bundle or shippings on a digital bundle, a schedule that mixes anchored and buffered entries, and invalid anchor, rebilling, cut-off, buffer or trial settings (for example Anchor date is not allowed for ad-hoc billing plans.). commitment_billing_count needs the plan feature, and survey_id must be a survey of the shop.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/plans \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "type": "subscription", "name": "name", "prices": [ { "ruleset_id": 1, "ranges": [ { "quantity": 1, "amount": 0 } ] } ], "discounts": [ { "ruleset_id": 1, "ranges": [ { "quantity": 1, "amount_off": 0, "percent_off": 0 } ] } ], "frequency_unit": "day", "frequency_count": 1, "shippings": [ { "add_unit": "day", "add_count": 1, "unit_day": 1, "unit_offset": 1 } ], "anchor_date": "2026-01-15", "rebilling_day": 1, "rebilling_day_of_month": 1, "rebilling_day_of_week": 1, "cut_off_days": 0, "cut_off_time": "cut_off_time", "charge_immediately": 0, "ship_immediately": 0, "buffer_days": 0, "trial_price": 0, "trial_length_days": 0, "trial_single_order": 0, "commitment_billing_count": 1, "charges_limit": 1, "survey_id": 1 }'
Response
{ "id": 1, "pricing": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "plan": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "pricings": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "variants": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Get bundle plan by ID

GET /bundles/{bundle_id}/plans/{plan_id}

Path parameters

bundle_idRequiredinteger

Bundle ID

plan_idRequiredinteger

Bundle plan ID

Query parameters

expand[]optionalstring[]

List of relations to expand in the response. Each expandable field on the response schema names its key, e.g. expand[]=customer. Nested keys use dot notation, e.g. items.product or subscriptions.items. Fields marked as always present are returned without being requested. An expanded list is null, not [], when there are no records. Unknown keys are ignored unless the endpoint says otherwise.

ReturnsBundlePlan

Bundle plan object response

Error responses

400object

The bundle is archived.

404object

No bundle with this ID exists in the shop, or no plan with this ID belongs to the bundle.

422object

expand is sent but is not an array, or one of its entries is not a string.

curl https://api.subbly.co/private/v1/bundles/{bundle_id}/plans/{plan_id} \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "pricing": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "plan": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "pricings": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "variants": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Update a bundle plan

PUT /bundles/{bundle_id}/plans/{plan_id}

Path parameters

bundle_idRequiredinteger

Bundle ID

plan_idRequiredinteger

Bundle plan ID

Request body

nameoptionalstring
pricesoptionalobject[]

Cannot be changed while the plan has active subscriptions. Prohibited when the bundle is configurable with no price_type. When sent, must contain exactly one entry per active bundle ruleset, with a first range quantity of 1 and the same set of range quantities across every ruleset.

discountsoptionalobject[]

Cannot be changed while the plan has active subscriptions. Only accepted when the bundle is configurable, has no price_type, and has a discount_type. Same per-ruleset range structure as prices.

shippingsoptionalobject[]

Prohibited for digital bundles. Every entry must use the same shape: all buffered (add_unit/add_count) or all anchored (unit_day/unit_offset). Bounds are validated against the plan's existing frequency_unit and frequency_count, which this endpoint cannot change.

cut_off_daysoptionalinteger | null

Required when the plan's shipping schedule is anchored (unit_day), prohibited otherwise. The anchored state comes from the shippings payload when sent, and from the stored schedule when it is not.

cut_off_timeoptionalstring | null

Time in HH:MM (24h). Defaults to 23:59 when cut_off_days is sent without it. Rejected for digital bundles, for non-anchored schedules, and when the shop's plan does not include the cut-off time feature.

charge_immediatelyoptionalinteger

Prohibited for digital bundles. Must be sent together with ship_immediately. Must be 1 when the stored plan has no rebilling day (ad-hoc billing).

Possible values: 0, 1.

ship_immediatelyoptionalinteger

Must be sent together with charge_immediately and cannot be 1 while charge_immediately is 0. Cannot be set to 0 while buffer_days is still set, so clear buffer_days in the same request.

Possible values: 0, 1.

buffer_daysoptionalinteger | null

Only accepted when the plan has exactly one shipment schedule entry, and only while ship_immediately is 1. Maximum is frequency_count multiplied by 1 for day, 7 for week, or 31 for month frequency.

trial_priceoptionalinteger | null

Prohibited on pre-order bundles and on plans with a rebilling day set. trial_price and trial_length_days must be sent together.

trial_length_daysoptionalinteger | null

Prohibited on pre-order bundles and on plans with a rebilling day set. trial_price and trial_length_days must be sent together.

trial_single_orderoptionalinteger

Can only be 1 on non-digital bundles and only when the plan has a trial length.

Possible values: 0, 1.

commitment_billing_countoptionalinteger | null

Only accepted when the shop's plan includes commitment billing.

charges_limitoptionalinteger | null
survey_idoptionalinteger | null

ReturnsBundlePlan

Bundle plan object response. Only variant, prices and discounts are populated; pricing and plan are always null on this response, so fetch the plan with GET and expand[]=plan to retrieve them.

Error responses

400object

The bundle or the plan is archived.

404object

No bundle with this ID exists in the shop, no plan with this ID belongs to the bundle, or the plan has no active product behind it (message Product not found), which is also what an archived plan returns in practice.

422object

The body fails validation. prices or discounts changes while a subscription plan has active subscriptions (The prices field cannot be changed while there are active subscriptions.), is not allowed for the bundle pricing setup, or does not have one entry per active ruleset. Subscription plans also fail on shippings for a digital bundle, a schedule that mixes anchored and buffered entries, invalid cut_off_days or cut_off_time, buffer_days with more than one shipment (Buffer days can only be set with a single shipment schedule.), trial fields on anchored plans or pre-order bundles, commitment_billing_count without the plan feature, or a survey_id that is not a survey of the shop.

curl -X PUT https://api.subbly.co/private/v1/bundles/{bundle_id}/plans/{plan_id} \ -H 'X-API-KEY: <api-key>' \ -H 'Content-Type: application/json' \ -d '{ "name": "name", "prices": [ { "ruleset_id": 1, "ranges": [ { "quantity": 1, "amount": 0 } ] } ], "discounts": [ { "ruleset_id": 1, "ranges": [ { "quantity": 1, "amount_off": 0, "percent_off": 0 } ] } ], "shippings": [ { "add_unit": "day", "add_count": 1, "unit_day": 1, "unit_offset": 1 } ], "cut_off_days": 0, "cut_off_time": "cut_off_time", "charge_immediately": 0, "ship_immediately": 0, "buffer_days": 0, "trial_price": 0, "trial_length_days": 0, "trial_single_order": 0, "commitment_billing_count": 1, "charges_limit": 1, "survey_id": 1 }'
Response
{ "id": 1, "pricing": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "plan": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "pricings": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "variants": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }

Archive a bundle plan

POST /bundles/{bundle_id}/plans/{plan_id}/archive

Archives a bundle plan. Rejected with 400 when the plan is already archived, when it is the bundle's last non-archived plan (error code last_active_plan), or when it still has active subscriptions (error code bundle_plan_has_active_subscriptions).

Path parameters

bundle_idRequiredinteger

Bundle ID

plan_idRequiredinteger

Bundle plan ID

ReturnsBundlePlan

Bundle plan object response. No relations are expanded on this response, so pricing, plan and variant are always null, and prices and discounts are always empty arrays.

Error responses

400object

The bundle or the plan is already archived (entity_archived), the plan is the last non-archived plan of the bundle (last_active_plan), or the plan still has active subscriptions (bundle_plan_has_active_subscriptions).

404object

No bundle with this ID exists in the shop, or no plan with this ID belongs to the bundle.

curl -X POST https://api.subbly.co/private/v1/bundles/{bundle_id}/plans/{plan_id}/archive \ -H 'X-API-KEY: <api-key>'
Response
{ "id": 1, "pricing": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "plan": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "variant": { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }, "pricings": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "pricing_name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "frequency_unit": "month", "frequency_count": 1, "anchored": true, "anchor_date": "2022-04-01", "rebilling_day": 1, "rebilling_day_of_week": 1, "rebilling_day_of_month": 1, "trial_price": null, "trial_length": null, "trial_single_order": true, "charge_immediately": true, "ship_immediately": true, "rebilling_start_at": "2022-04-01", "cut_off_at": "2022-04-01", "cut_off_time": "23:59", "cut_off_days": 0, "buffer_days": 0, "stock_count": 100, "setup_fee": null, "pre_order_end_at": "2022-04-01", "shippings": [ {} ], "metadata": [ {} ], "survey": {}, "commitment_billing_count": 0, "charges_limit": 0, "plan_hash": "a1b2c3d4", "published": true, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "variants": [ { "id": 1, "bundle_plan_id": 1, "bundle_plan": {}, "name": "Yellow T-shirt with pokemon print", "description": "Yellow T-shirt with pokemon print", "price": 799, "price_schema": {}, "price_scheme": {}, "parent": {}, "product": {}, "metadata": [ {} ], "attributes": [ {} ], "options": [ {} ], "stock_count": 100, "published": true, "inventory_item_id": 1, "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "prices": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "discounts": [ { "id": 1, "ruleset_id": 1, "plan_id": 1, "ranges": [ {} ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" } ], "created_at": "2022-04-01T00:00:00.000000Z", "updated_at": "2022-04-01T00:00:00.000000Z" }
paginationobject
dataBundle[]
createoptionalobject[]
createoptionalobject[]
createoptionalobject[]
createoptionalobject[]

Each min must be less than or equal to max (max null means unbounded) and mins must be distinct. For ruleset_type=quantity the ranges must not overlap. For ruleset_type=total the ranges must be contiguous: the lowest must start at 0, each next min must equal the previous max plus 1, and the highest must have max null.

createoptionalobject[]
idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

createoptionalobject[]
deleteoptionalobject[]
createoptionalobject[]

A bundle may hold only one filter in total, so delete the existing filter in the same request before creating a new one.

deleteoptionalobject[]
createoptionalobject[]
updateoptionalobject[]
deleteoptionalobject[]
createoptionalobject[]

Judged against the final set after create, update and delete are applied. Each min must be less than or equal to max (max null means unbounded) and mins must be distinct. For ruleset_type=quantity the ranges must not overlap. For ruleset_type=total the ranges must be contiguous: the lowest must start at 0, each next min must equal the previous max plus 1, and the highest must have max null.

updateoptionalobject[]

Ids must belong to this bundle, must not be archived and must be distinct.

deleteoptionalobject[]

Ids must belong to this bundle, must not be archived and must be distinct. At least one active ruleset must remain after the request, and a ruleset with active subscriptions cannot be deleted.

createoptionalobject[]

The bundle total after deletes and creates must not exceed 5 images.

updateoptionalobject[]
deleteoptionalobject[]
idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

metafield_idoptionalinteger

Filter by metadata ID. Only preset metadata with single_line_string data type are supported. Required unless attribute_id is given.

attribute_idoptionalinteger

Alias for metafield_id. Required unless metafield_id is given.

valuesRequiredinteger[]

Metadata value IDs to filter by. Each ID must exist.

paginationobject
dataBundleItem[]
createoptionalobject[]
idinteger
product_idintegerDeprecated

Deprecated. Use variant_id instead.

bundle_idinteger
productVariant | nullDeprecated

Expandable link to the variant. Null unless requested via expand.

variant_idinteger
variantVariant | null

Expandable link to the variant. Null unless requested via expand.

settingsBundleItemSetting[]
extra_priceinteger | null

Additional price for this bundle item

stock_countinteger | null

Available stock for this item

quantityinteger | null

Quantity of this item in the bundle. Always null on configurable bundles.

positioninteger | null

Display position of this item. Null when never set.

created_atstring

Format: date-time.

updated_atstring

Format: date-time.

variant_idRequiredinteger

Product variant ID. Must be a non-archived one-time product variant belonging to the shop (not a gift card, not a bundle), must not already be an item of this bundle, and must not repeat within the same create array.

quantityoptionalinteger | null

Prohibited when the bundle is configurable; sending it returns 422 "Quantity is not available for configurable bundles."

positionoptionalinteger | null
extra_priceoptionalinteger | null

Extra price in cents. Only available for configurable bundles; sending it on a non-configurable bundle returns 422 "Extra price is only available for configurable bundles."

settingsoptionalobject | null

Only available for configurable bundles whose selection type is not "single"; sending it otherwise returns 422.

createBundleItem[]
idinteger
product_idintegerDeprecated

Deprecated. Use variant_id instead.

bundle_idinteger
productVariant | nullDeprecated

Expandable link to the variant. Null unless requested via expand.

variant_idinteger
variantVariant | null

Expandable link to the variant. Null unless requested via expand.

settingsBundleItemSetting[]
extra_priceinteger | null

Additional price for this bundle item

stock_countinteger | null

Available stock for this item

quantityinteger | null

Quantity of this item in the bundle. Always null on configurable bundles.

positioninteger | null

Display position of this item. Null when never set.

created_atstring

Format: date-time.

updated_atstring

Format: date-time.

createoptionalobject[]
updateoptionalobject[]
deleteoptionalobject[]
idinteger
product_idintegerDeprecated

Deprecated. Use variant_id instead.

bundle_idinteger
productVariant | nullDeprecated

Expandable link to the variant. Null unless requested via expand.

variant_idinteger
variantVariant | null

Expandable link to the variant. Null unless requested via expand.

settingsBundleItemSetting[]
extra_priceinteger | null

Additional price for this bundle item

stock_countinteger | null

Available stock for this item

quantityinteger | null

Quantity of this item in the bundle. Always null on configurable bundles.

positioninteger | null

Display position of this item. Null when never set.

created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
product_idintegerDeprecated

Deprecated. Use variant_id instead.

bundle_idinteger
productVariant | nullDeprecated

Expandable link to the variant. Null unless requested via expand.

variant_idinteger
variantVariant | null

Expandable link to the variant. Null unless requested via expand.

settingsBundleItemSetting[]
extra_priceinteger | null

Additional price for this bundle item

stock_countinteger | null

Available stock for this item

quantityinteger | null

Quantity of this item in the bundle. Always null on configurable bundles.

positioninteger | null

Display position of this item. Null when never set.

created_atstring

Format: date-time.

updated_atstring

Format: date-time.

paginationobject
dataBundleGroup[]
idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

createoptionalobject[] | null
deleteoptionalobject[] | null
idinteger
namestring
slugstring
digitalboolean
delivery_infostring | null
configurableboolean
imagesProductImage[]
descriptionstring | null
hidden_itemsboolean
searchableboolean
show_ruleset_nameboolean
quantity_selectorsinteger[] | null
selection_typestring | null

Possible values: variant, product, single_product.

discount_typestring | null

Possible values: per_item, total, percentage.

price_typestring | null

Possible values: per_item, total.

ruleset_typestring | null

Possible values: total, quantity.

appearance_typestring | null

Possible values: one_step, two_step, without_ruleset, after_checkout.

rulesetsBundleRuleset[]
plansBundlePlan[]
preferencesBundlePreference[]
filtersBundleFilter[]
discountsBundleDiscount[]
pricesBundlePrice[]
tagsstring[]
tags_metaTags

Tags with their IDs. Always present; does not need to be requested via expand.

setup_feeinteger | null
gifting_enabledboolean
pause_enabledboolean
pre_order_end_atstring | null

Format: date.

funnel_idinteger | null
change_product_collection_idinteger | null

ID of the product collection used for cross-product plan switching.

collect_shipping_addressboolean
publishedboolean
items_countinteger
plans_countinteger
rulesets_countinteger
metadataEntityMetadata[] | null
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

ruleset_idRequiredinteger
rangesRequiredobject[]
ruleset_idRequiredinteger
rangesRequiredobject[]
add_unitoptionalstring

Buffered shipping unit. Required when unit_day is absent; prohibited when any entry uses unit_day. Restricted by frequency_unit: day frequency allows only day, week frequency allows day and week, month frequency allows all three.

Possible values: day, week, month.

add_countoptionalinteger

Buffered shipping count. Required with add_unit; prohibited when any entry uses unit_day. Range depends on add_unit: -1 to the number of days in one billing cycle for day (-1 means same-day shipping), 0 to frequency_count (or frequency_count x 4 for non-weekly frequency) for week, 0 to frequency_count for month.

unit_dayoptionalinteger

Anchored shipping day. Required when add_unit is absent. Must be 1 to frequency_count for day frequency, 1-7 for week frequency, 1-31 for month frequency.

unit_offsetoptionalinteger

Anchored shipping offset. Required with unit_day. Must be between 0 and frequency_count - 1.

idinteger
pricingPlan | nullDeprecated

Expandable. Single pricing object (for subscription products). Deprecated - use 'plan' instead.

planPlan | null

Expandable. Single plan object (for subscription products)

variantVariant | null

Expandable. Single variant object (for one-time products)

pricingsPlan[] | nullDeprecated

Deprecated - always returns null

variantsVariant[] | nullDeprecated

Deprecated - always returns null

pricesBundlePrice[]
discountsBundleDiscount[]
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
pricingPlan | nullDeprecated

Expandable. Single pricing object (for subscription products). Deprecated - use 'plan' instead.

planPlan | null

Expandable. Single plan object (for subscription products)

variantVariant | null

Expandable. Single variant object (for one-time products)

pricingsPlan[] | nullDeprecated

Deprecated - always returns null

variantsVariant[] | nullDeprecated

Deprecated - always returns null

pricesBundlePrice[]
discountsBundleDiscount[]
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

ruleset_idRequiredinteger
rangesRequiredobject[]
ruleset_idRequiredinteger
rangesRequiredobject[]
add_unitoptionalstring

Buffered shipping unit. Required when unit_day is absent; prohibited when any entry uses unit_day. Restricted by frequency_unit: day frequency allows only day, week frequency allows day and week, month frequency allows all three.

Possible values: day, week, month.

add_countoptionalinteger

Buffered shipping count. Required with add_unit; prohibited when any entry uses unit_day. Range depends on add_unit: -1 to the number of days in one billing cycle for day (-1 means same-day shipping), 0 to frequency_count (or frequency_count x 4 for non-weekly frequency) for week, 0 to frequency_count for month.

unit_dayoptionalinteger

Anchored shipping day. Required when add_unit is absent. Must be 1 to frequency_count for day frequency, 1-7 for week frequency, 1-31 for month frequency.

unit_offsetoptionalinteger

Anchored shipping offset. Required with unit_day. Must be between 0 and frequency_count - 1.

idinteger
pricingPlan | nullDeprecated

Expandable. Single pricing object (for subscription products). Deprecated - use 'plan' instead.

planPlan | null

Expandable. Single plan object (for subscription products)

variantVariant | null

Expandable. Single variant object (for one-time products)

pricingsPlan[] | nullDeprecated

Deprecated - always returns null

variantsVariant[] | nullDeprecated

Deprecated - always returns null

pricesBundlePrice[]
discountsBundleDiscount[]
created_atstring

Format: date-time.

updated_atstring

Format: date-time.

idinteger
pricingPlan | nullDeprecated

Expandable. Single pricing object (for subscription products). Deprecated - use 'plan' instead.

planPlan | null

Expandable. Single plan object (for subscription products)

variantVariant | null

Expandable. Single variant object (for one-time products)

pricingsPlan[] | nullDeprecated

Deprecated - always returns null

variantsVariant[] | nullDeprecated

Deprecated - always returns null

pricesBundlePrice[]
discountsBundleDiscount[]
created_atstring

Format: date-time.

updated_atstring

Format: date-time.