Managing Inventory
Basic Inventory Concepts
You as a seller may sell the same product in many different ways.
Two copies of a book for sale may both be in used condition, but show very different signs of use.
Or you sell many copies of one book in new condition, with some stored in one warehouse and some in another warehouse (such that handling and transport times differ).
The Kaufland marketplace permits you to save an id_offer on inventory units to uniquely identify different units of the same product, so these similar units can be tracked and managed independently of one another.
Every inventory change is performed with respect to a single storefront.
Inventory changes performed directly by REST API specify the storefront, and adding an inventory CSV file requires specifying which storefront the file pertains to.
If you are selling on multiple storefronts, units will be connected via your id_offer.
When units are connected by id_offer, we ensure that their warehouse and quantity are kept in sync.
Other properties of connected units are allowed to differ by storefront and are not kept in sync (e.g., prices, shipping group, handling time, note).
If you don't want inventory and warehouse to be considered as shared information between two units, they must have different id_offer.
In order to minimize erroneous synchronization of quantity and warehouse, we will reject attempts to create a unit if we already store a unit with same id_offer and different EAN or condition, or which is fulfilled by Kaufland.
id_offer field must be UNIQUE across the seller's entire inventory.
For example, if you use the
id_offer value "xyz-123" to offer a product,
then you cannot use the same id_offer value "xyz-123" for any other offer
unless offering same Product in a different storefront.
Creating Units
Once you have added an product to the Kaufland marketplace (see the Managing Product Data page), or if the product already exists on the site, you need to add your inventory information. There are two ways to do this:
- REST API: use the
/units/endpoint to upload inventory data one product at a time. - CSV Files: use the
/import-files/REST API endpoints to send inventory data for multiple products at once.
Adding new inventory with the REST API
The simplest way to update your inventory data is to send JSON requests to the /units/ REST API
endpoint. However, you can only update one product at a time this way, so far large volumes of changes,
sending CSV files is more efficient.
To use this endpoint, you need to send a POST request with a JSON object that describes your
inventory. Here's an example JSON object:
{
"id_product": 35903281,
"ean": "4011905437873",
"condition": "NEW",
"listing_price": 5999,
"minimum_price": 5100,
"amount": 200,
"note": "",
"id_offer": "AB1234",
"handling_time": 2,
"id_warehouse": "1345",
"id_shipping_group": "3457",
"storefront": "de",
"vat_indicator": "standard_rate",
"eco_participation": 99,
"battery_participation": 100,
"manufacturer_guarantee_years": 2,
}
Here are explanations for each property of the object:
-
id_product: The internal Kaufland ID of the product. You must either specify anid_productorean(or both). -
ean: The EAN of the product. You must either specify anid_productorean(or both). -
condition: "NEW" means that the product is not used. The available conditions are listed below. -
listing_price: The price you would like to sell the product at, in integral cents in the currency of the storefront (CZK or EUR or PLN). This value must be greater than zero, and has a maximum that differs by currency (maximum 25 million CZK, 1 million EUR or 4.5 million PLN). -
minimum_price: The minimum price you would be willing to sell at, in integral cents of the storefront currency. If this property is specified, the price of your inventory will automatically be adjusted. Only relevant if you want to use Smart Pricing. -
amount: How many of the product you have in stock. Note that amount is limited to 99999. -
note: A note about the products condition for the customer. This gives some extra details for used products. This is limited to 250 characters. -
id_warehouse: The warehouse ID the product is located in. Required for non-EU sellers with more than one warehouse, or for EU sellers with more than one warehouse with at least one non-EU warehouse. If not specified, your default warehouse will be used — if no default warehouse is configured, the request will be rejected. -
id_offer: Your internal ID for the unit (offer and unit are synonyms on the Kaufland marketplace). Whatever you set here will be included in the unit, but not the product data. This is used to identify units which should be connected over several storefronts. Read more here. -
handling_time: The amount of working days till the order is handed over to the carrier. (Always use withtransport_time, which is part of the shipping group.) Has to be equal to or bigger than zero [>=0]. -
id_shipping_group: ID of the shipping group the unit should be assigned to. -
storefront: The storefront parameter indicates on which marketplace the offer should be placed. -
vat_indicator: VAT indicator determining the VAT rate of the unit. The indicator should match the available VAT indicator of the storefront. You can find the most recent VAT indicator mapping at the/vat-indicators/REST API endpoint. -
eco_participation: The Eco-Participation value in eurocents (integer). If provided, has to be bigger than zero [>0]. Only relevant for specific products on the French storefront. -
battery_participation: The Battery-Participation value in eurocents (integer). If provided, has to be bigger than zero [>0]. -
manufacturer_guarantee_years: Duration of the manufacturer guarantee in years (integer). If provided, has to be bigger than zero [>0] and cannot exceed 99.
If you get a 201 response code, then the unit was created successfully. Otherwise,
you should get a JSON object back with an error message in the message property, for example:
{
"message": "Can not decode body"
}
Note: The POST /units/ endpoint should be used to add new units to an product. However, if you send
data for an product for which you already have a unit, it might update the existing unit, instead of creating a
new unit. Here are the rules for what happens:
When a new unit is created:
- You have no existing units for the product on the same storefront.
- You have existing units for the product on the same storefront, and they do not have an
id_offerset, and the newly submitted unit has noid_offer, but the new unit has a differentconditionthan all of the existing units. - You have existing units for the product on the same storefront, and they do not have an
id_offerset, but the new unit has anid_offer. - You have existing units for the product on the same storefront, and they have an
id_offerset, but the new unit has a differentid_offer. - You have existing units for the product on the same storefront, and they have an
id_offer, but you send a new unit without anid_offer.
When an existing unit is updated:
- You have existing units for the product on the same storefront, and they do not have an
id_offerset, and the newly submitted unit has noid_offer, but the new unit has the sameconditionas one of the existing units. - You have existing units for the product on the same storefront, and they have an
id_offerset, and the new unit has the sameid_offeras one of the existing units.
Available Conditions
| String | Integer |
|---|---|
| "NEW" | 100 |
| "USED___AS_NEW" | 200 |
| "USED___VERY_GOOD" | 300 |
| "USED___GOOD" | 400 |
| "USED___ACCEPTABLE" | 500 |
| "REFURBISHED___AS_NEW" | 110 |
| "REFURBISHED___VERY_GOOD" | 120 |
| "REFURBISHED___GOOD" | 130 |
| "REFURBISHED___ACCEPTABLE" | 140 |
Updating inventory with CSV files
Since you can only add or update one product at a time through the /units/ REST API endpoint,
it can be more efficient to send a batch file with many units in it. There are two types of inventory CSV files:
- INVENTORY FEED file: a full dump of your entire inventory. Details about this type of file are available on the Inventory CSV Files page.
- INVENTORY COMMAND file: a list of commands to alter your existing inventory in the Kaufland marketplace. Details about this type of file are available on the Inventory CSV Files page.
Allowed VAT indicators
Each storefront has a set of eligible VAT indicators for units. Use the /vat-indicators/
endpoint to find the allowed VAT indicators and their corresponding VAT rates for a storefront. For example, the
German storefront allows 'standard_rate' and 'reduced_rate_1' indicators, corresponding to 19% and 7% VAT
rates respectively. Order units will have a VAT rate in the vat field corresponding to the VAT indicator
provided for the unit.
Retrieving Units
You can get a list of all of your own units by sending a GET request to the
/units/ endpoint. Note: it can take
several minutes for units to show up in this list after they are created.
Checking Whether Units Are Live
Unit responses include an is_live boolean field that indicates whether your offer is
currently visible and active on the storefront. Unlike the status field, which only
reflects the unit's own state, is_live takes all factors into account - including
product data validity and blocklisting. Use is_live: true as the single reliable
signal that your offer is live on Kaufland.
Retrieving Not-Live Reasons
If is_live is false for one of your units, you can retrieve the specific
reason(s) by sending a POST request to the
/units/status REST API endpoint,
passing the unit IDs in the JSON request body as unit_ids. The lookup is scoped to a
single storefront, so query each storefront your units are listed on separately:
POST /units/status?storefront=de
Content-Type: application/json
{ "unit_ids": [1, 2, 999] }
The response will be a 200 with an array of objects, each one representing the result
for a single unit:
{
"data": [
{
"id_unit": 1,
"status_code": 200,
"is_live": false,
"reasons": [
{
"reason": "stock_update_needed",
"reason_description": "The stock quantity is set to zero. Please update your stock to reactivate the offer."
},
{
"reason": "product_data_incomplete",
"reason_description": "Some product data is incomplete or needs review. Please review and update the product data.",
"details_url": "https://www.kauflandglobalmarketplace.com/en/seller-university/selling/product-data/general/"
}
]
},
{
"id_unit": 2,
"status_code": 200,
"is_live": true,
"reasons": []
},
{
"id_unit": 999,
"status_code": 404,
"message": "Unit not found"
}
]
}
The id_unit and status_code combination can be used to determine whether
the unit was found. The table below explains what each status code stands for:
| Status code | Representation | Description |
|---|---|---|
| 200 | Success | The unit was found. is_live and reasons (empty if live) are included. |
| 404 | Unit not found |
No unit with this id_unit exists on the requested storefront. A unit
that is listed on a different storefront is also reported as not found, so check the
storefront you queried before assuming the unit was deleted. Only
id_unit, status_code and message are included.
|
Each entry in reasons has the following fields:
| Field | Description |
|---|---|
reason |
Machine-readable identifier of the reason. See Not-Live Reason Codes for the full list. |
reason_description |
Human-readable description of the reason, in English. Intended to be shown to the seller, not parsed by software. |
details_url |
(Optional) Link with more information for the seller. Only present where available - its absence is not an error. |
Important:
-
Your request must not contain more than 20 unit IDs in the
unit_idsarray; exceeding the limit rejects the whole request with a400rather than returning a partial result. See the endpoint reference for the fullunit_idsrules. -
This endpoint is intended for on-demand lookups (e.g. triggered by a seller check or a support
flow), not for default or bulk polling. Requests are rate-limited, see the
Rate limits page. To learn when a unit stops being live
without polling, subscribe to the
item_unit_not_livepush notification and call this endpoint for the unit it reports. -
If the reasons for a unit that is not live cannot be determined, the whole request fails
rather than returning an incomplete
reasonslist:503when the downstream service is unavailable or times out,500for any other downstream failure. Both are safe to retry, and neither means "this unit has no reasons".
Not-Live Reason Codes
The reason values that
/units/status can return, with the
reason_description and, where one exists, the details_url sent alongside
each of them:
| Reason | Reason description | More info |
|---|---|---|
unverified_authenticity |
The authenticity of this product could not be confirmed. | Seller guidelines |
image_usage_issue |
The image usage rights for this product could not be confirmed. | Product data guideline |
intellectual_property_issue |
A potential intellectual property concern has been identified. | Seller guidelines |
brand_authorization_issue |
Your authorisation to sell this brand could not be confirmed. | Seller guidelines |
other_compliance_issue |
This offer doesn't currently meet the General Terms and Conditions of Kaufland Global Marketplace. | Seller guidelines |
regulatory_review |
The product does not comply with our General Terms and Conditions. | Seller guidelines |
price_check_needed |
The listed price needs a quick check. Please review and update the price. | Offers |
product_data_mismatch |
Some product data doesn't match the item listed. Please review and update the product data. | Product data |
divid_number_needed |
This offer is subject to the Single-Use Plastics Fund Act. Please register on the EPR compliance page in the Seller Portal to activate this offer. | EPR general information |
idu_number_needed |
This offer is subject to the French IDU number requirement. Please register on the EPR compliance page in the Seller Portal to activate this offer. | EPR France |
epr_number_needed |
This offer is subject to the Extended Producer Responsibility (EPR) requirement. Please register on the EPR compliance page in the Seller Portal to activate this offer. | EPR general information |
gpsr_info_needed |
This offer needs the contact details of an EU-based responsible person under the GPSR. Please add the name, address, phone number, and e-mail address to continue. | GPSR |
weee_number_needed |
This offer needs a valid WEEE registration number. Please add one in the Seller Portal to continue. | EPR general information |
ioss_threshold |
Offers under €150 shipped from outside the EU will be paused from 1 July 2026 under IOSS regulations. | Offers |
recommerce_eligibility |
This offer isn't currently eligible for recommerce. Please contact Seller Support for more information. | Seller guidelines |
eco_fee_pending |
The EPR eco fee for this offer is still being calculated. It will go live automatically once the calculation is complete and all pending issues are resolved. | EPR management by Kaufland |
account_documentation_needed |
Some account documentation, such as your VAT ID, needs to be updated. Please update your details in the Seller Portal. | Formal framework |
product_data_incomplete |
Some product data is incomplete or needs review. Please review and update the product data. | Product data |
stock_update_needed |
The stock quantity is set to zero. Please update your stock to reactivate the offer. | Offers |
offer_paused |
This offer is currently paused. Please reactivate it to make it visible again. | Offers |
unknown_reason |
This offer is currently not live. Please contact Seller Support for more information. | - |
New reasons may be added over time - this is a non-breaking change. Always fall back to
displaying reason_description for reasons you do not recognize yet, rather than
failing the request.
Updating Units
To update a single unit, send a PATCH request to the /units/{id_unit}/
REST API endpoint, replacing {id_unit} in the URL with the internal Kaufland ID of the unit. The
body of the request should contain a JSON object, similar to the JSON you send to create a new unit,
with one difference: you cannot change the id_product or id_offer of a unit. To change
those properties, you must delete the unit and create a new one.
Note: you can also update units by sending a POST request to the
/units/ endpoint. See the above
note on updating with a POST request for details.
Updating Units in Bulk
To update multiple units within the same request you can send a POST request to the /units/bulk
REST API endpoint, the body of the request should contain an array of JSON objects where each one represent a single unit update, each unit request object would look like the following (The example uses handling time, Please refer to the following page for a full list of fields):
[
{
"unit_id": 12345,
"unit_data": {
"handling_time": 1
}
}
]
This will update the handling time of the unit with id 12345, upon a successful request (not a successful unit update, rather the whole request succeeded) the return code will be 207 which means Multi Status and the response will be an array of objects each one representing the result of a unit update, with a successful unit update the response should look like the following example:
{
"data": [
{
"id_unit": 12345,
"status_code": 200,
"unit": {
"id_unit": 12345,
"status": "AVAILABLE",
"currency": "EUR",
"condition": "NEW",
"note": null,
"id_warehouse": null,
"id_shipping_group": null,
"id_offer": null,
"listing_price": 100,
"minimum_price": 100,
"price": 100,
"id_product": 1,
"amount": 1,
"date_inserted_iso": "2023-11-30T00:00:00.000Z",
"date_lastchange_iso": "2023-11-30T00:00:00.000Z",
"handling_time": 1,
"shipping_rate": 1,
"storefront": "DE",
"transport_time_min": 1,
"transport_time_max": 1,
"fulfillment_type": "fulfilled_by_merchant",
"is_live": true
}
}
]
}
The id_unit and status_code combination can be used to determine whether the unit was successfully updated or not, the table below explain what each status code stands for as well as an example response:
| Status code | Representation | Example |
|---|---|---|
| 200 | Success |
|
| 400 | Validation error |
|
| 404 | Unit Not found |
|
| 500 | Internal server error |
|
Important: There are a couple of rules to keep in mind when using this endpoint, failure to respect these rules will result in the failure of the entire request:
- Your request SHOULD NOT have more than 150 units in the body, exceeding this limit will result in a 400 response and will fail the whole request.
- The request SHOULD NOT contain duplicate units, if duplicates are detected the whole request is rejected.
Note: Sending an empty request with just {"data": []} will result in an empty response [] and won't fail the request. Status code will still be 207.
Full example
The following is an example of a request that will contain three unit updates, where one will update successfully, the second will fail with a validation error and the third one will fail with an internal server error in order to demonstrate the three different cases combined:
The request body:
[
{
"id_unit": 12345,
"unit_data": {
"handling_time": 4,
}
},
{
"id_unit": 45678,
"unit_data": {
"listing_price": 0,
}
},
{
"id_unit": 68576,
"unit_data": {
"note": "",
}
}
]
The response:
{
"data":[
{
"id_unit":12345,
"status_code":200,
"unit":{
"id_unit":12345,
"status":"AVAILABLE",
"currency":"EUR",
"condition":"NEW",
"note":null,
"id_warehouse":null,
"id_shipping_group":null,
"id_offer":null,
"listing_price":100,
"minimum_price":100,
"price":100,
"id_product":1,
"amount":1,
"date_inserted_iso":"2023-11-30T00:00:00.000Z",
"date_lastchange_iso":"2023-11-30T00:00:00.000Z",
"handling_time":4,
"shipping_rate":1,
"storefront":"DE",
"transport_time_min":1,
"transport_time_max":1,
"fulfillment_type":"fulfilled_by_merchant",
"is_live":true
}
},
{
"id_unit":45678,
"status_code":400,
"message":"Parameters [listingPrice] are missing or have wrong value.",
"errors":[
{
"field":"listing_price",
"message":"listing_price must be greater than 0"
}
]
},
{
"id_unit":68576,
"status_code":500,
"key":"internal_server_error",
"message":"Internal server error"
}
]
}
Deleting Units
To delete a unit, send a DELETE request to the /units/{id_unit}/
endpoint, replacing {id_unit} in the URL with the internal Kaufland ID of the unit.
Retrieving Single Units
You can get the stored information for a single unit if you have its ID. Just send a GET request to
the /units/{id_unit}/ endpoint, replacing
{id_unit} in the URL with the internal Kaufland ID of the unit.