Skip to content

Conversation

@Jeremie-Kiwik
Copy link
Contributor

@Jeremie-Kiwik Jeremie-Kiwik commented Nov 5, 2025

Questions Answers
Description? Add Product Combinations admin API endpoints (CRUD, stock, suppliers, images, searches)
Type? improvement
BC breaks? no
Deprecations? no
Fixed ticket?
Sponsor company KIWIK
How to test? See below

EDIT

Changed endpoints to match the new ADR convention
#109

Endpoints summary

GET /products/combinations/{combinationId}
PATCH /products/combinations/{combinationId}
DELETE /products/combinations/{combinationId}

POST /products/{productId}/combinations
GET /products/{productId}/combinations/ids
GET /products/{productId}/combinations
DELETE /products/{productId}/combinations/bulk-delete

PATCH /products/combinations/{combinationId}/stocks
GET /products/combinations/{combinationId}/stock-movements

PATCH /products/combinations/{combinationId}/suppliers
GET /products/combinations/{combinationId}/suppliers

PATCH /products/combinations/{combinationId}/images
PATCH /products/combinations/{combinationId}/images/clears

GET /products/{productId}/combinations/search
GET /products/combinations/associations/search

How to test

Create an API Client with these scopes: product_read & product_write
Request an access token

0. Create a product

  • Method: POST
  • URI: /admin-api/products
  • Body:
{
  "productType": "combinations",
  "names": {
    "fr-FR": "Test combinated product"
  }
}

Get the product ID in the response. We will use it as {productId} for other calls

1. Generate product combinations

(GenerateProductCombinationsCommand command)

Will add 4 combinations, with:

  • attribute group 'Size' (id_attribute_group = 1)

    • Size M (id_attribute = 2)
    • Size L (id_attribute = 3)
  • attribute group 'Color' (id_attribute_group = 2)

    • Color Red (id_attribute = 10)
    • Color Blue (id_attribute = 14)
  • Method: POST

  • URI: /admin-api/products/{productId}/combinations

  • Body:

{
  "groupedAttributeIds": {
    "1": [2, 3],
    "2": [10, 14]
  }
}
  • Response:
    HTTP Code: 201
    HTTP Body: object with combinations containing 4 combinations, and totalCombinationsCount

Please note the 4 combinationId, we will use them below. Let's call them {combinationId_1}, ..., {combinationId_4}, in ascending order.

You should see the combinations in back office too.

2. Get combinations IDs

(GetCombinationIds command)

  • Method: GET
  • URI: /admin-api/products/{productId}/combinations/ids
  • Response:
    HTTP Code: 200
    HTTP Body: array of { "combinationId": number } with our 4 Ids

3. Update a combination

(UpdateCombinationCommand command)

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId_1}
  • Body (example):
{
  "isDefault": true,
  "reference": "REF-001",
  "gtin": "3519690900332",
  "isbn": "978-3-16-148410-0",
  "mpn": "MPN-123",
  "upc": "72527273070",
  "impactOnWeight": 0.15,
  "impactOnPrice": 1.99,
  "ecoTax": 0.2,
  "impactOnUnitPrice": 0.3,
  "wholesalePrice": 12.5,
  "minimalQuantity": 2,
  "lowStockThreshold": 5,
  "availableDate": "2025-12-31T00:00:00+00:00",
  "availableNowLabels": {
    "fr-FR": "En stock",
    "en-GB": "In stock"
  },
  "availableLaterLabels": {
    "fr-FR": "Bientôt",
    "en-GB": "Later"
  }
}
  • Response:
    HTTP Code: 200
    HTTP Body: updated combination

4. Get all combinations detail

(GetEditableCombinationsList command)

  • Method: GET
  • URI: /admin-api/products/{productId}/combinations
  • Response:
    HTTP Code: 200
    HTTP Body: { productId, combinations: [...], totalCombinationsCount }

5. Get single combination detail

(GetCombinationForEditing command)

  • Method: GET
  • URI: /admin-api/products/combinations/{combinationId_1}
  • Response:
    HTTP Code: 200
    HTTP Body: full combination details (pricing, labels, dates, identifiers)

6. Delete a single combination

(DeleteCombinationCommand command)

Let's delete the 'L - size' / 'Red - color' combination:

  • Method: DELETE
  • URI: /admin-api/products/combinations/{combinationId_3}
  • Response:
    HTTP Code: 204
    HTTP Body: none

7. Bulk delete combinations

(BulkDeleteCombinationCommand command)

Let's delete now all the blue combinations:
(change {combinationId_x} in the body with real values)

  • Method: PUT
  • URI: /admin-api/products/{productId}/combinations/bulk-delete
  • Body:
{
  "combinationIds": [{combinationId_2}, {combinationId_4}]
}
  • Response:
    HTTP Code: 204
    HTTP Body: none

8. Update combination stock

(UpdateCombinationStockAvailableCommand command)

Fixed quantity

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId_1}/stocks
  • Body (fixed quantity):
{
  "location": "somewhere",
  "fixedQuantity": 42
}
  • Response:
    HTTP Code: 200
    HTTP Body: updated combination id, with updated quantity + location
  • Validation error (if both fixed and delta provided):
    HTTP Code: 422

On back-office, you should see a quantity of 42 for the combination.

Delta quantity

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId_1}/stocks
  • Body (delta quantity):
{
  "deltaQuantity": -10
}
  • Response:
    Same as fixed quantity

On back-office, you should see a quantity of 32 for the combination.

9. Get stock movements

(GetCombinationStockMovements command)

  • Method: GET
  • URI: /admin-api/products/combinations/{combinationId_1}/stock-movements?limit=5
  • Response:
    HTTP Code: 200
    HTTP Body: array of movements (type, dates, ids, deltaQuantity, employeeName)

10. Update suppliers for a combination

(UpdateCombinationSuppliersCommand command)

Before testing, suppliers must be linked to the product.
The endpoint to associate suppliers with a product has not been implemented yet. It must be done manually from the back office:

  • go to the product
  • "Options" tab
  • Check the 2 suppliers "Accessories supplier" + "Fashion supplier"
    • save
  • (This will also create a line in DB for the product's combinations, with default values and price = 0)

Here we go: update information.

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId_1}/suppliers
  • Body (example):
{
  "combinationSuppliers": [
    {
      "supplier_id": 1,
      "currency_id": 1,
      "reference": "SUP-REF-001",
      "price_tax_excluded": "10.50"
    },
    {
      "supplier_id": 2,
      "currency_id": 1,
      "reference": "SUP-REF-002",
      "price_tax_excluded": "20.00"
    }
  ]
}
  • Response:
    HTTP Code: 200
    HTTP Body: updated suppliers list for the combination

11. Get suppliers associated to a combination

(GetCombinationSuppliers command)

  • Method: GET
  • URI: /admin-api/products/combinations/{combinationId_1}/suppliers
  • Response:
    HTTP Code: 200
    HTTP Body: array of suppliers (productSupplierId, productId, supplierId, supplierName, reference, priceTaxExcluded, currencyId, combinationId)

12. Associate images to a combination

(SetCombinationImagesCommand command)

First add 3 random images to the product {productId}, on the back office. We will then add 2 of them to the combination

Get the associated id_image in DB. We will use them as {imageId_1}, {imageId_2} and {imageId_3}.

If you don't have access to the DB, reload the page then inspect the DOM of the image to get the data-id

You will have something like:

<div class="dz-preview is-cover dz-complete dz-image-preview" data-id="27">

Your id is 27

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId_1}/images
  • Body:
    (replace {imageId_x} with the real values)
{
  "imageIds": [{imageId_1}, {imageId_3}]
}
  • Response:
    HTTP Code: 200
    HTTP Body: updated combination (at least combinationId, imageIds)

On back-office, you should see that 2 images are linked to the combination (with a black border around the images)

13. Remove all images from a combination

(RemoveAllCombinationImagesCommand command)

  • Method: PATCH
  • URI: /admin-api/products/combinations/{combinationId}/images/clears
  • Response:
    HTTP Code: 200
    HTTP Body: updated combination (at least combinationId)

On back-office, images are no more linked to the combination (no black border around them)

14. Search combinations (scoped to a product)

(SearchProductCombinations command)
Will search combinations with for example, a given string in attributes

  • Method: GET
  • URI: /admin-api/products/{productId}/combinations/search?phrase=rouge&limit=5

Note: The search strings are localized. So if you have an English PS, please test search?phrase=red instead, like this:
/admin-api/product/{productId}/combinations/search?phrase=red&limit=5

  • Response:
    HTTP Code: 200
    HTTP Body:
{
  "productId": {productId},
  "combinations": [
    { "combinationId": x, "combinationName": "xxxx" }
  ]
}

If you search for a non-existent string, combinations should be empty.

15. Search combinations for association (global search)

(SearchCombinationsForAssociation command)

Important note: this search DOES NOT search in attribute names; it searches product/combination name and references (like ref, ean13, upc, mpn, isbn, supplier_reference...)

  • Method: GET
  • URI: /admin-api/products/combinations/associations/search?phrase=REF&limit=5
  • Response:
    HTTP Code: 200
    HTTP Body: array of { productId, combinationId, name, reference, imageUrl }
    Or an empty array if nothing is found

@jf-viguier
Copy link
Contributor

nice PR ! whaou ! 15 endpoints

@kpodemski
Copy link
Contributor

Hello @Jeremie-Kiwik

Thank you for this PR. There are a few errors in the integration tests, looks like some typos in the paths, could you take a look?

@ps-jarvis ps-jarvis moved this from Ready for review to Waiting for author in PR Dashboard Nov 11, 2025
@Jeremie-Kiwik
Copy link
Contributor Author

@kpodemski : ah sorry, I thought those were internal errors in the deployment of the test environments. I didn’t really look into it any further.
The unit tests are now OK

@nicosomb
Copy link
Contributor

@Jeremie-Kiwik there is a conflict on your PR.

@kpodemski
Copy link
Contributor

Hello @Jeremie-Kiwik

Thanks for fixing the conflicts, the last step is making sure to have the CI 🟢. Thank you 🙏🏻

@kpodemski kpodemski added the Invalid This doesn't seem right label Jan 23, 2026
@kpodemski
Copy link
Contributor

Hello @Jeremie-Kiwik

Just a quick heads-up: reviews on pending Admin API PRs will start in the coming days.

We first took some time to clarify and unify the Admin API contribution rules and ADR expectations. With that work done, the team will now review existing PRs based on those updates.

Please note that, based on the updated standards described here:
https://devdocs.prestashop-project.org/9/admin-api/contribute-to-core-api/

some aspects of this PR currently do not meet the requirements. For this reason, I've added the Invalid label for now.

Someone from the team will take a closer look at the PR and provide concrete suggestions on how it can be adjusted to align with the new guidelines.

Thanks for your patience. Feedback will follow directly on the PR.

@TomasEm
Copy link

TomasEm commented Jan 30, 2026

Hi,
please, forgive me my lack of knowledge of push request procedure.
Can I ask for timeline of this PR to be integrated in main release? As it is important, I can wait, but not for a long time.
thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: Waiting for author

Development

Successfully merging this pull request may close these issues.

6 participants