Updating Prices

Overview

Use the Prices API to set or update the price of any article in the Zalando Catalog.

Prices must be specified for each product_simple or EAN. Prices are set separately for each sales channel in which the article is available for sale (such as zalando.de or zalando.co.uk).

You may optionally set a promotional price to alert customers that an article is on sale and you may also optionally provide schedules (with specific start and end times) for each article.

Price updates go through a pipeline that validates and eventually processes them, leading to the new prices being visible in the store. The Price API only performs basic pre-validation and a complete price validation is performed asynchronously. This means the Price API does not wait on the result of the validation to respond to requests, so having a price update accepted by the API does not mean it will pass the full set of validations.

To check the results of price validations we provide the Manage Prices UI in zDirect. It allows you to see the latest price updates that have been fully processed, which have raised warnings or errors, and those which are still waiting to be processed. Alternatively, you can connect to the Price Reporting API.

The Prices API is write-only. To get the current price of a product, use the Product Status Report in zDirect.

Price API specification

  • Prices API reference: Information on scopes, rate limiting, and sandbox behavior.

  • OpenAPI reference for the Prices API.

Non-Euro Currency

For all sales channels that use a currency other than the euro (EUR), you must convert all prices to the target currency yourself and submit the converted value as the price. The zDirect Platform does not perform any currency conversion.

Different currencies can be subject to a different set of rules on the validation pipeline. To guarantee a good customer experience, we recommend submitting EUR prices first before submitting non-EUR prices.

Czech Koruna (CZK)

Prices should not have decimal subunits other than ,00 (e.g. 750,00 or 1300,00).

Hungarian Forint (HUF)

Prices should be in incremental steps of 5 (e.g. 12000 or 20105) and not have decimal subunits other than ,00 (e.g. 12000,00 or 20105,00).

Update the Price of an Article

There are two steps to update article prices:

  1. Create a price update JSON to specify the updates you wish to make, and
  2. Submit the JSON file to zDirect with the Prices API.

If the price update is submitted for an EAN which already exists in the Zalando Catalog, the price update is immediately sent to be validated. If the EAN is not in the Zalando Catalog, the price update will be held and passed on to be validated once the article is associated with a Zalando SKU (waiting room concept). To check the status of an EAN, use the Products API as described in Checking if an Article Exists in the Zalando Catalog. After validation, prices are propagated to the fashion store if no problem was identified, otherwise, they must be fixed accordingly (see Price Validation System for more information).

Create a Price Update JSON

Prices may be set per article or in batch updates. A single price update JSON may include up to 1,000 EANs for a single Merchant ID.

This is the basic structure of the prices update JSON:

{
  "product_prices": [
    {
      "ean": "$EAN_1",
      "sales_channel_id": "$SALES_CHANNEL",
      "regular_price": {
        "amount": $AMOUNT,
        "currency": "$CURRENCY_CODE"
      },
      "ignore_warnings": $BOOLEAN
    },
    {
      "ean": "$EAN_2",
      "sales_channel_id": "$SALES_CHANNEL",
      "regular_price": {
        "amount": $AMOUNT_1,
        "currency": "$CURRENCY_CODE"
      },
      "promotional_price": {
        "amount": $AMOUNT_2,
        "currency": "$CURRENCY_CODE"
      },
      "scheduled_prices": [
        {
          "regular_price": {
            "amount": $AMOUNT_3,
            "currency": "$CURRENCY_CODE"
          },
          "promotional_price": {
            "amount": $AMOUNT_4,
            "currency": "$CURRENCY_CODE"
          },
          "start_time": "$START_TIME",
          "end_time": "$END_TIME"
        }
      ],
      "ignore_warnings": $BOOLEAN
    }
  ]
}

Price Update JSON Requirements

General Requirements

  • One JSON may include a maximum of 1,000 price entries on product_prices.
  • The price updates must all be for a single Merchant ID.
  • Except for the promotional_price and scheduled_prices fields, all the other fields and values are mandatory.
  • Each combination of ean and sales_channel_id in the product_prices list must be unique.

EAN

The ean of the article should already exist in the Zalando Catalog. In case the ean does not exist in the Zalando Catalog, the price update is delayed until the ean is added to the Catalog.

Sales Channel ID

Use the Sales Channels API to get the available sales channels for a merchant. For more information, and for a list of sales channels codes, see Sales Channels API.

Regular Price

  • The value of amount must be greater than 0.
  • The value of currency must be one of the following ISO 4217 currency codes:
Currency ISO 4217 Currency Code
Euro EUR
Swiss Franc CHF
Polish Złoty PLN
Norwegian Krone NOK
Swedish Krona SEK
Danish Krone DKK
Pound Sterling GBP
Czech Koruna CZK
Romanian Leu RON
Hungarian forint HUF

Warning

The currency MUST correspond to the country you are attempting to set the price in, otherwise your price update will be rejected on validation process!

Promotional Price

For each article per sales channel, you may set a promotional price in addition to the regular price by including the promotional_price field in addition to the regular_price value.

Setting a value for promotional_price makes the following changes to how the article is displayed:

  • The article shows the regular price crossed out with the sales price listed in red.
  • The percentage reduction from the regular price is displayed near the price.
  • The article will be visible in the "Sale" section of the Zalando Fashion Store.

If this price update was not part of a schedule, then when the promotional period has ended, you must set the article back to its standard price by submitting a new update with the regular_price field entered as normal, and with no promotional_price field.

The promotional_price field has the following requirements:

  • The promotional price amount value must be greater than 0.
  • The difference between the promotional price and the regular price must be at least 0.01.
  • The promotional price must be less than the regular price.
  • The promotional price must have the same currency type as the regular price.

Scheduling

By using the scheduling feature you can steer when and for how long the price of your article should be online. Each article in the request can have a list of scheduled prices associated with it. A schedule contains a regular_price and an optional promotional_price. It must have a start_time, but it is optional to provide and end_time. If no end_time is provided, then the scheduled price will remain active until it is replaced by another price update or overwritten by another schedule.

start_time and end_time must be in ISO-8601 extended date-time format with an offset from UTC, as defined by RFC 3339, section 5.6, with a resolution up to a microsecond. Examples: "2021-02-02T16:30:15.000Z", "2021-02-02T17:30:15.000+01:00".

Submitting a new price update for an EAN overrides all the existing schedules with the ones provided in the new update. This means that sending a new price update without any schedules will remove any existing schedules for the EAN.

If the base price of the price update is rejected due to being invalid or if the update fails to be applied due to an internal error, then all the schedules will be rejected too and will not be applied.

If one schedule is rejected due to being invalid, then all the schedules will be rejected too and will not be applied.

  • The maximum number of schedules per article is 3.
  • The regular_price and promotional_price must follow the same rules described above.
  • The start_time must be a least 120 minutes after the price update request submission time.
  • There must be a minimum of 60 minutes between any 2 start_times provided.
  • As a start_time you can only use a date/time in the future, not from the past.
  • If an end_time is provided, there must be a minimum of 60 minutes between the start_time and the end_time.
  • If an end_time is provided, it can't be younger than the start_time

Enforcing Warnings

The Price Validation System has three severity levels: INFO which never causes a price update to be rejected, WARNING and ERROR which always causes a price update to be rejected. You must always fix the errors but you can choose to ignore warnings using the mandatory ignore_warnings field.

We recommend always using ignore_warnings with a false value to protect your price requests from possible mistakes. The option to leave the field as true for all requests is not recommended.

If a price update had a WARNING raised but you still want it to be accepted, you can set the ignore_warnings field to true. We recommend only setting this field to true for this specific case where a WARNING is raised and you should use it as false again right after this price was fixed.

Price Update JSON Example

This example illustrates a JSON that would update the price of two EAN in the same sales channel. The first EAN contains one schedule and the second EAN contains a promotional price:

{
  "product_prices": [
    {
      "ean": "5901234123457",
      "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
      "regular_price": {
        "amount": 89.95,
        "currency": "EUR"
      },
      "scheduled_prices": [
        {
          "regular_price": {
            "amount": 89.95,
            "currency": "EUR"
          },
          "promotional_price": {
            "amount": 50,
            "currency": "EUR"
          },
          "start_time": "2020-05-01T14:00:00Z",
          "end_time": "2020-05-05T22:00:00Z"
        }
      ],
      "ignore_warnings": false
    },
    {
      "ean": "6661234123457",
      "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
      "regular_price": {
        "amount": 59.95,
        "currency": "EUR"
      },
      "promotional_price": {
        "amount": 24.95,
        "currency": "EUR"
      },
      "ignore_warnings": false
    }
  ]
}

Use the Prices API to POST the JSON

Authentication

The zDirect API requires OAuth 2.0 authentication for all API calls. Use the Authentication API to generate access tokens as described in the Authentication section.

Submit the JSON

Use the Prices API to submit the JSON:

POST /merchants/{$MERCHANT_ID}/prices

The following httpie command will POST the file price_update.json to zDirect:

http POST \
https://api-sandbox.merchants.zalando.com\
/merchants/e18e458a-de38-40ee-8119-4130eed7486a/prices \
"Authorization:Bearer $YOUR_ACCESS_TOKEN" \
< price_update.json

Response: Successful

After successful execution of the POST, you receive an HTTP 207 response code. This multi-status response provides a status, code, and optional description value for every price update in the request.

Note

A 207 response cannot be taken in itself as an indication of success. You may receive a 207 response to submissions with errors. The status value following each entry on product_prices field must be separately parsed.

Here is an example response:

{
  "results": [
    {
      "product_price": {
        "ean": "5901234123457",
        "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
        "regular_price": {
          "amount": 89.95,
          "currency": "EUR"
        },
        "scheduled_prices": [
          {
            "scheduled_price": {
              "regular_price": {
                "amount": 89.95,
                "currency": "EUR"
              },
              "promotional_price": {
                "amount": 50,
                "currency": "EUR"
              },
              "start_time": "2020-05-01T14:00:00Z",
              "end_time": "2020-05-05T22:00:00Z",
              "status": "ACCEPTED",
              "code": 0,
              "description": null
            }
          }
        ],
        "ignore_warnings": false
      },
      "status": "ACCEPTED",
      "code": 0,
      "description": null
    },
    {
      "product_price": {
        "ean": "6661234123457",
        "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
        "regular_price": {
          "amount": 59.95,
          "currency": "EUR"
        },
        "promotional_price": {
          "amount": 24.95,
          "currency": "EUR"
        },
        "scheduled_prices": [],
        "ignore_warnings": false
      },
      "status": "ACCEPTED",
      "code": 0,
      "description": null
    }
  ]
}

The status value ACCEPTED indicates that the price update is queued, and will be applied if the EAN exists in the Zalando Catalog and is valid, otherwise it will be queued until the EAN is added to the Catalog, and then validated and applied.

Warning

Price updates can take up to 60 minutes to be applied, depending on the load. There might be situations when we are experiencing a higher load than usual, which causes the time for price updates to be applied to exceed 60 minutes. This happens approximately once or twice a month.

Response: Unsuccessful

400 (Bad Request)

You will receive an HTTP 400 (Bad Request) response in the following circumstances:

  • One or more required fields are missing
  • The product_prices list in the request body is empty
  • The product_prices list in the request body includes more than 1,000 items
  • The JSON includes one or more duplicates of a combination of ean and sales_channel_id.

207

Most other invalid submissions are rejected with a multi-status HTTP 207 response code which enumerates the reason for rejection.

In this example, a price update reuqest was rejected because the regular price amount was zero:

{
  "results": [
    {
      "product_price": {
        "ean": "5901234123457",
        "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
        "regular_price": {
          "amount": 0,
          "currency": "EUR"
        },
        "scheduled_prices": [],
        "ignore_warnings": false
      },
      "status": "REJECTED",
      "code": 101,
      "description": "Regular price amount 0 is not greater than 0."
    }
  ]
}

In this example, a base price update request was accepted, but the schedules were rejected because one of the schedules had a duration that was too short:

{
  "results": [
    {
      "product_price": {
        "ean": "5901234123457",
        "sales_channel_id": "01924c48-49bb-40c2-9c32-ab582e6db6f4",
        "regular_price": {
          "amount": 70,
          "currency": "EUR"
        },
        "promotional_price": null,
        "scheduled_prices": [
          {
            "scheduled_price": {
              "regular_price": {
                "amount": 70,
                "currency": "EUR"
              },
              "promotional_price": {
                "amount": 60,
                "currency": "EUR"
              },
              "start_time": "2020-08-01T14:00:00Z",
              "end_time": "2020-08-01T14:05:00Z",
              "status": "REJECTED",
              "code": 101,
              "description": "Schedule duration is too short. Provided duration: 5 minutes. Minimum allowed schedule duration: 60 minutes."
            }
          },
          {
            "scheduled_price": {
              "regular_price": {
                "amount": 70,
                "currency": "EUR"
              },
              "promotional_price": {
                "amount": 50,
                "currency": "EUR"
              },
              "start_time": "2020-08-01T16:00:00Z",
              "end_time": "2020-10-05T17:00:00Z",
              "status": "REJECTED",
              "code": 101,
              "description": "There was at least one invalid schedule, so all schedules will be rejected."
            }
          },
          {
            "scheduled_price": {
              "regular_price": {
                "amount": 70,
                "currency": "EUR"
              },
              "promotional_price": {
                "amount": 40,
                "currency": "EUR"
              },
              "start_time": "2020-08-01T18:00:00Z",
              "end_time": "2020-10-05T19:00:00Z",
              "status": "REJECTED",
              "code": 101,
              "description": "There was at least one invalid schedule, so all schedules will be rejected."
            }
          }
        ],
        "ignore_warnings": false
      },
      "status": "PARTIALLY_ACCEPTED",
      "code": 105,
      "description": "Update Partially Successful: Base Price accepted, check scheduled_prices field for scheduled price update results"
    }
  ]
}

When price updates are rejected, it usually indicates there is something wrong with the request (as specified in the description field). However, price updates can also sometimes be rejected with code 102. This indicates that an internal error occurred in the Prices API. In that case, it is advised to wait at least an hour and then try to resubmit the price update.

Contact Support