Skip to main content

Update a Bundle

Change a bundle's details, replace its products, swap or drop its cover, and publish or unpublish it.


Endpoint​

PUT /api/v3/bundles/{bundle}

Path Parameters​

ParameterTypeDescription
bundlestringThe bundle's id, or its external_id when id_type=external is set

Query Parameters​

ParameterTypeDefaultDescription
id_typestringinternalinternal (bundle id) or external (external_id)
includestring-Comma-separated: products, prices, availability. See Included blocks
fieldsstring-Comma-separated list of fields to return, e.g. id,published. Applied after include

Request Body​

Updates are partial: only the fields present in the payload are validated and written. A field you do not send keeps its value, so renaming a bundle never touches its products, cover, state or external_id.

note

The verb is PUT, but the semantics are a merge, not a replacement: fields absent from the payload are left untouched rather than cleared.

FieldTypeNotes
namestringMax 255 characters. Cannot be null
productsarrayReplaces the whole composition, in the order sent. From 2 to 100, each once. See Replacing the products
products_id_typestringinternal (default) or external, how products names the products. See Products by identifier
descriptionstringMax 2,000 characters
slugstringMax 255 characters
external_idstringMax 64 characters, unique in your store. Send null to clear it. Resending the bundle's own external_id, in any case, is accepted
publishedbooleantrue publishes, false unpublishes. See Publishing
privatebooleanSee States
cover_urlstringDownloads a new cover. null drops the bundle's own cover. Not accepted together with cover. See Cover
coverstringStorage path of a new uploaded cover. null drops the bundle's own cover. Not accepted together with cover_url. See Cover

published_at is not accepted, as on create: the platform sets it.

An external_id already used by another bundle of your store answers 422 with A bundle with this external_id already exists.


Replacing the Products​

Send products to replace the composition. The rules are the same as on create: from 2 to 100 products, each once, named by position when one fails. Leave products out to keep the current composition as it is.

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/318" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "products": [1207, 1201] }'

Send products_id_type: external to list them by identifier instead, as described under Products by identifier.

Products the bundle already has are kept as they are, whether you send them by ID or by identifier. A product that stopped being sellable after it was added (it was withdrawn from sale, for example) does not block an update that sends it again: the bundle keeps it, and with ?include=products the response shows its rejection_reason. A product new to the bundle must be sellable, so that same product is refused when you add it to another bundle.

A bundle that keeps an unsellable product stays unavailable. While it is unpublished, it cannot be published until you replace that product.


Publishing​

You sendOn a bundle that isResult
published: trueunpublishedPublishes it, when it can be sold with the products it has after the request
published: true without productsalready publishedKeeps it published as it is, without checking whether it can be sold
published: true with productsalready publishedKeeps it published, when it can be sold with the new products
published: falseanyUnpublishes it. Always allowed, also on a bundle that cannot be sold
no publishedanyLeaves the state as it is

Publishing a bundle that is already published keeps its original published_at; the date does not move. So an integration that sends published: true again without products does not fail when one of the products has stopped being sellable since. When the request also carries products, the bundle is checked again with those products. The update is saved, and the response reports that the bundle cannot be sold in availability when the request asks for ?include=availability.

When the bundle cannot be sold, a published: true that checks it answers 422 under published, naming each reason with its availability code, and nothing in the request is saved, including the other fields it carried:

{
"message": "The bundle cannot be published: some of its products cannot be sold in a bundle (ineligible_products).",
"errors": {
"published": [
"The bundle cannot be published: some of its products cannot be sold in a bundle (ineligible_products)."
]
}
}

A bundle saved as a single-product draft from the dashboard answers the same way:

{
"message": "The bundle cannot be published: it has fewer than 2 products (below_minimum_products).",
"errors": {
"published": [
"The bundle cannot be published: it has fewer than 2 products (below_minimum_products)."
]
}
}

To publish such a draft, send its complete products together with published: true.

Example: Publish​

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/318" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "published": true, "private": false }'

Cover​

You sendResult
cover_url with a URLDownloads the image and replaces the bundle's cover
cover with a storage pathReplaces the bundle's cover with that uploaded image
cover_url: null or cover: nullDrops the bundle's own cover: it goes back to the collage of its products
neitherKeeps the current cover

The image rules are listed under Covers.

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/318" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "cover_url": null }'

Request Examples​

Rename, Found by external_id​

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/rock-icons?id_type=external" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "name": "Rock Icons: The Complete Set" }'

Change or Clear the external_id​

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/318" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "external_id": "rock-icons-2026" }'

Send "external_id": null to clear it.

Unpublish​

curl -X PUT "https://yourstore.publica.la/api/v3/bundles/318" \
-H "X-User-Token: your-api-token" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{ "published": false }'

Response​

200 OK with the updated bundle object under data. It carries products, prices and availability only when the request names them in include, computed after the update.


Errors​

StatusCondition
401Missing or invalid X-User-Token
403Selling is disabled for the store (Selling is disabled for this store.), or the token does not belong to an administrator. A token without access gets 403 even for a bundle that does not exist
404The bundle does not exist in your store, checked before the payload is validated
422Validation failure: name sent as null, fewer than 2 or more than 100 products, a product repeated, not found, ambiguous or not sellable, published: true on a bundle that cannot be sold, published_at sent, an external_id used by another bundle, cover and cover_url together, a cover that cannot be downloaded or is not a supported image, or an include other than products, prices or availability or sent as an array. Nothing is saved
429Rate limit exceeded (20 requests per minute per token, shared with create and with the create and update endpoints of the Add-ons API)

See Also​

X

Graph View