Onboarding New Products

Overview

If you used the Products API and found that a product you wish to sell does not yet exist in the Zalando Catalog, you may add it using the Product Attributes API and the Product Submissions API.

The basic steps for onboarding a new product are:

  1. Determine which product outline to use.
  2. Use the Product Attributes API to get the outline.
  3. Begin creating a product submission JSON based on our template.
  4. Use the Product Attributes API to get details on the requirements for each attribute value that you will specify.
  5. Use the Product Submissions API to submit the product submission JSON to Zalando.

Warning

When you submit a product for (a) correcting mistakes or (b) adding new Variants/Sizes, you must always provide the entire product including all its new and existing Variants/Sizes.

  1. If we find any problems with your submission during validation, correct them and resubmit your product.
  2. Use the Product Status Report (PSR) to monitor the validation status of your product submissions.
  3. Once your product is approved, you may set price and available stock.

Note that this process may be run concurrently for many products at the same time. As soon as a product is approved, you may set its price and stock, and you do not need to wait for all products to be approved.

There are a lot of details to track in this process, so we have prepared a Products Onboarding Cheatsheet as a reference. It includes summaries of most of the main ideas and useful charts and resources.

It is important to note that in some cases a product attribute may be optional in the zDirect API, but you may be legally required to specify its value.

For example, some product specifications are required by law in the EU, such as declaring the use of certain material types in garments. The attributes that define those values may be optional.

Be sure that you understand the regulations pertaining to the products that you are selling, and that you are in compliance with all applicable laws.

Key Concepts

Product Outlines

A product outline (or product silhouette) is a JSON that enumerates all of the mandatory and optional attributes that are used to define a product of a particular type.

Each type of Zalando product (such as shirt or sandals) has a corresponding outline that includes all of its attributes. This allows us to set requirements for each product definition that are appropriate to its type. For example, the shirt outline includes neckline, while sandals outline includes heel_from.

The attributes in each outline are organized into three tiers: product_model, product_config, and product_simple.

For more information on the product data structure, see Understanding Products.

Restricted Attributes

Note

Each outline has a restriction on certain attributes that can be found under restricted_attributes.

The restricted_attributes is a dynamic object and not shown when all values of an attribute are allowed. For example, the attribute condition allows 2 different values on a global level. Both of them can be used within sandals without restriction. The attribute washing_instructions allows 20 different values on a global level. However, within the outline sandals only 4 of them should be used. These 4 are shown in restricted_attributes.

Validation Hints

Note

Currently, this feature is visible only for select merchants as a pilot.

validation_hints is a field containing hints about attributes on a particular tier of the outline. Currently, it can hint on the "Mandatory If Applicable" attributes. Generally, "mandatory if applicable" attributes are mandatory, but depending on your product this attribute may not apply. In that case, a special value not_applicable can be supplied, which will indicate this during the submission validation process.

Product Outline Example

The following is the outline for the product model sandals:

Click to show all sandals details
{
  "label": "sandals",
  "tiers": {
    "model": {
      "optional_types": [],
      "mandatory_types": [
        "target_age_groups",
        "target_genders",
        "name",
        "brand_code",
        "size_group"
      ],
      "restricted_attributes": []
    },
    "config": {
      "optional_types": [
        "condition",
        "color_code.secondary",
        "color_code.tertiary",
        "width",
        "shape",
        "decksohle",
        "material.filling",
        "futter",
        "heel_form",
        "insole_technology",
        "material_construction",
        "non_textile_but_animal_parts",
        "occasion",
        "padding_type",
        "pattern",
        "shoe_detail",
        "shoe_toecap",
        "shoe_width",
        "size_fits",
        "sole_material",
        "sport_qualities",
        "sport_shoe_details",
        "sport_shoe_insole",
        "sport_shoe_outer_sole",
        "sport_shoe_outer_sole_technology",
        "sport_type",
        "upper_material",
        "washing_instructions"
      ],
      "mandatory_types": [
        "color_code.primary",
        "media",
        "season_code",
        "supplier_color",
        "description"
      ],
      "restricted_attributes": [
        {
          "type": {
            "label": "washing_instructions",
            "version": "1.0.0"
          },
          "values": [
            "washing_instructions_4106",
            "washing_instructions_4107",
            "washing_instructions_6999",
            "washing_instructions_7858"
          ]
        },
        ...
      ],
      "validation_hints": {
        "material.filling": {
          "hint_type": "mandatory_if_applicable",
          "description": {
            "en": "Please specify the material composition if the product has filling."
          },
          "related_types": []
        },
        ...
      }
    },
    "simple": {
      "optional_types": [
        "metric.heel_height",
        "metric.platform_height",
        "metric.schafthoehe",
        "metric.schaftweite"
      ],
      "mandatory_types": [
        "ean",
        "size_codes"
      ],
      "restricted_attributes": []
    }
  },
}

Product Submission JSON

Each product is submitted as a JSON payload with the Product Submissions API. Each product submission JSON must specify a single product with all of its product_config and product_simple variants.

The product outline shown above is similar to a submission JSON, but there are some differences in formatting and layout. For more information on the requirements for creating a product submission JSON, see Create a product submission JSON below.

Images

Each product submission requires a set of product images. Each product in the Zalando Catalog has one set of images. Different merchants may not use different sets of images for the same product.

For more information, see Images below.

Implementation Best Practice

The current process for submitting new products has many steps. It is possible to manually construct a product submission JSON, but doing so may be time consuming, especially if you have a large number of products to onboard.

We recommend building a UI layer on top of the Product, Product Attributes, and Product Submissions API to simplify the process. Reading through this section will help you understand how the process works, and how the APIs can be used in a custom solution.

Improvements to the product onboarding experience are currently in development.

Note

We recommend updating all attributes once a month, since they might change. For breaking changes though, we will reach out beforehand to your technical contacts in zDirect.

Sandbox Testing

The Products Attributes and Product Submissions APIs support sandbox mode.

Warning

Read operations in the sandbox and production environments will return different data. Regardless of the merchant, the sandbox environment provides all available outlines and attribute types, but only generic attribute values.

For more information, see the Sandbox section of the Product Attributes API Overview in our API Reference.

Warning

Product submissions made in the sandbox environment are not persisted or propagated. New products submitted in the sandbox will not be visible in your Product Status Report, and they will not be added to the Zalando Catalog.

Product submissions made during sandbox testing will be subjected to the first stage of automated validation as described in Submission and Validation. If you receive an HTTP 200 OK response upon sandbox submission, you can be confident that your JSON is well formed, that you did not omit any required attributes. Additional validation only takes place in the production environment.

For more information, see the Sandbox section of the Products API Overview.

Step 0: 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.

Step 1: Determine Which Outline to Use

The first step to product submission is deciding which product outline to use. We recommend starting with the Silhouette Guide Introduction in Zalando Partner University. From that page, you can also access specific guides.

If you are not certain which outline to use, you may get all outlines in one large file and browse through it to find the best fit. Once you know which outline to use, you may get the outline using the Product Attributes API.

Step 2: Get One or All Outlines

To get a specific outline, use the Products API. An httpie request for the sandals outline looks like this:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/outlines/sandals" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

You will receive the sandals model outline shown above in response.

You may also use the Product Attributes API to request all outlines available to your merchant account. Using httpie, you would send the following command:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/outlines" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

The reply is a large JSON with a set of outlines for different product models.

Step 3: Create a product submission JSON

Once you have the correct outline, you will build a JSON defining the product attributes.

The product outline enumerates all optional and mandatory attributes for your product type. Add each attribute that you specify to the submission template in the product_model_attributes, product_config_attributes, and product_simple_attributes tiers, as appropriate.

You will then use the Product Attributes API to gather more data on the requirements of each attribute value. For several examples of how to do this, see Examples below.

Warning

Any string values in the submitted JSON might have leading/trailing whitespace characters trimmed off. This is to avoid scenarios where duplicate submissions are created because one of them has an extra space at the beginning/end.

Product Submission JSON Template

This template illustrates the basic structure of a product submission JSON. You may use it as a basis for constructing your submission file, or as a reference in writing your own code to generate submission JSON files.

Click to show JSON template
{
  "outline":"$MODEL_LABEL",
  "product_model":{
    "merchant_product_model_id":"$YOUR_MERCHANT_PRODUCT_MODEL_ID",
    "product_model_attributes":{
      "name":"$MODEL_NAME",
      "brand_code":"$MODEL_BAND_CODE",
      ...
    },
    "product_configs":[
      {
        "merchant_product_config_id":"$YOUR_MERCHANT_PRODUCT_CONFIG_ID",
        "product_config_attributes":{
          "color_code.primary":"$CONFIG_COLOR_CODE.PRIMARY",
          "media":[
            {
              "media_path":"URL",
              "media_sort_key":"$SORT_KEY"
            },
            {
              "media_path":"URL",
              "media_sort_key":"$SORT_KEY"
            }
          ],
          "season_code":"fs20",
          "supplier_color":"white",
          ...
        },
        "product_simples":[
          {
            "merchant_product_simple_id":"$YOUR_MERCHANT_PRODUCT_SIMPLE_ID",
            "product_simple_attributes":{
              "ean":"$EAN",
              ...
            }
          }
        ]
      }
    ]
  }
}

To see a full example of a valid submission, see Sample Submission JSON in our Products Onboarding Cheatsheet.

Step 4: Specify Attribute Values

Use the product outline to add all of the mandatory attribute types and any optional attribute types you wish to specify to your product submission JSON. Be sure to enter all mandatory types, and do not include any attribute type that is not in the outline you are using.

To provide attribute values, you have to first learn what the requirements are for the various types. Some values must be strings, for example, or integers, or values chosen from a list. Some attributes allow multiple values.

To find out more about those requirements, use the Product Attributes API. The attributes used for image submission and product size options are treated separately in their own sections below.

Note

The description attribute at the config level accepts plain text only. HTML tags are not supported.

Warning

The description attribute map accepts only individual locale to description entries. It can be in any of the supported languages and has to be keyed by its corresponding locale. This description will only be displayed at Zalando stores from countries using this locale. The description field is mandatory and looks like:

{ 
  "description": 
    { 
      "it": "..." 
    } 
}

Get Attribute Requirements

The Product Attributes API provides endpoints for learning more about each attribute.

Type Path Main Uses
GET ​/merchants​/{merchant_id}​/attribute-types​/{type_label} Return the schema for the specified attribute type.
GET ​/merchants​/{merchant_id}​/attribute-types​/{type_label}​/attributes Return all attributes of the specified attribute type.
GET ​/merchants​/{merchant_id}​/attribute-types​/{type_label}​/attributes​/{attribute_label} Return the specified attribute of the specified attribute type.

Their responses will be JSON objects describing the attribute and they types using the following fields:

Field Description
cardinality Indicates if one or many responses are allowed.
definition The expected data type of the value.
description Any additional information about the attribute type.
label Other calls may reference the attribute type by referencing the value of this field.
name A human-readable description of the field for use in referencing the attribute type in front ends or UIs.
type_variants Some attribute types have variants that are independently defined, such as color_code.primary and color_code.secondary. An outline may only allow some of the possible variants.
usage Either literal or reference_by_label. For literal, enter a value. For reference_by_label, the specification takes a label value to specify the value.

Attribute Requirements Examples

Basic Example: name

Here is an example for the simple attribute type name using the httpie command:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/name \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

The response:

{
  "label": "name",
  "name": {
    "en-gb": "name"
  },
  "type_variants": [],
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "usage": "literal"
}

Based on the schema information seen in the previous section, we can deduce the following:

  • label: API calls may reference this attribute as name.
  • name: This attribute type should be referred to as name in any UI or front end.
  • type_variants: The empty array tells us that no type variants exist for this attribute type.
  • cardinality: A single value is expected rather than a list.
  • definition: The expected data type of this attribute type is string.
  • usage: Any valid string may be used for this value. If a predefined value was required, this value would be reference_by_label instead of literal.

Based on this information, we can conclude that the expected attribute value for this type is free text. The following example shows a valid value for name in a submission JSON:

"name": "AIR FORCE SANDALS 1 '07 LV8 UTILITY"

reference_by_label Example: brand code

Many attribute values must be selected from a defined set or the JSON will fail validation. Such attributes always include "usage": "reference_by_label" in their schema.

brand_code is one example of a reference_by_label attribute. It is a product_model attribute that identifies the product brand.

As with name, we begin by using the following httpie command to request the schema:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/brand_code" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

This is the response:

{
  "label": "brand_code",
  "name": {
    "en": "brand code"
  },
  "description": {
    "en": "Brand code is used to identify the Brand of the product"
  },
  "type_variants": [],
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "usage": "reference_by_label"
}

Note that the usage value is reference_by_label.

When you are working with a reference_by_label attribute, call the following endpoint to find out what values may be used using httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/brand_code/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Here is an abbreviation of the long response:

{
   "items":[
      {
         "label":"ns1",
         "name":{
            "en":"Nike Sportswear"
         },
         "value":{
            "string":"ns1"
         }
      },
      {
         "label":"A55",
         "name":{
            "en":"adidas Consortium by Y's"
         },
         "value":{
            "string":"A55"
         }
      },
      {
         "label":"A56",
         "name":{
            "en":"adidas by Raf Simons"
         },
         "value":{
            "string":"A56"
         }
      },
      ...
   ]
}

To specify a brand_code in your product submission JSON, enter one of the available label values as the value. For example, to specify the Nike Sportswear brand, enter the following:

"brand_code": "ns1"

Example: target genders

The product_model attribute target_genders is also reference_by_label, so the attribute value must be selected from a list. To request the type schema with httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/target_genders" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

In this case, our response is:

{
  "label": "target_genders",
  "name": {
    "en": "target genders"
  },
  "description": {
    "en": "Target genders"
  },
  "type_variants": [],
  "cardinality": "many",
  "definition": {
    "type": "StringDefinition"
  },
  "usage": "reference_by_label"
}

Note that the value of "cardinality" is "many". This tells us that a list of attribute values is required, although the list may contain only one member. To get possible label values with httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/target_genders/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

That gives us the following response:

{
  "items": [
    {
      "label": "target_gender_male",
      "name": {
        "en": "target gender male"
      },
      "value": {
        "string": "target_gender_male"
      }
    },
    {
      "label": "target_gender_female",
      "name": {
        "en": "target gender female"
      },
      "value": {
        "string": "target gender_female"
      }
    }
  ]
}

To specify that a product is intended for any gender, enter the following into your submission JSON:

"target_genders": [
  "target_gender_male",
  "target_gender_female"
]

Type Variants Example: color_code.primary

The next mandatory config attribute attribute is color_code.primary.

We can immediately tell from the . in the type label that color_code.primary is a variant of the color_code type. All type variants of one attribute type uses the same schema, and differ only in the label. To get the type schema with httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/color_code.primary" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

The response:

{
  "label": "color_code",
  "name": {
    "en-gb": "color_code"
  },
  "type_variants": [
    {
      "label": "primary",
      "name": {}
    },
    {
      "label": "secondary",
      "name": {}
    },
    {
      "label": "tertiary",
      "name": {}
    }
  ],
  "cardinality": "one",
  "definition": {
    "type": "LocalizedStringDefinition"
  },
  "usage": "reference_by_label"
}

Note that the API returned the schema for the more general color_code, which includes an array of type variants including color_code.primary, color_code.secondary, and more. To use httpie to get more information on the attributes of this schema:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/color_code/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Here is an abbreviation of the long response, which contains the entire set of colors. Response filtering for attribute requests is not currently supported.

{
  "items": [
    {
      "label": "001",
      "name": {
        "en-gb": "001"
      },
      "value": {
        "localized": {
          "se": "vit",
          "fr": "blanc",
          "pt": "branco",
          "cs": "bílá",
          "it": "bianco",
          "nl": "wit",
          "de": "weiss",
          "sv": "vit",
          "da": "hvid",
          "en": "white",
          "es": "blanco",
          "fi": "valkoinen",
          "no": "hvit",
          "pl": "bialy"
        }
      }
    },
  ...
  ]
}

To set your primary color code to white in your submission JSON, add the following value, taken from the label field:

"color_code.primary": "001"

Optional Attribute Example: color_code.secondary

In many cases, the product outline includes optional attributes that you may not wish to specify.

For example, assume you do not wish to specify the optional color_code.secondary attribute, you can leave its attribute type definition out of your submission JSON.

Complex Attribute Example: material.upper_material_clothing

The product_config attribute type material.upper_material_clothing defines the type of material that makes up the upper part of the product.

Like color_code, this attribute has multiple type variants. Using httpie, we could request its schema with this command:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/material.upper_material_clothing" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Or like this:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/material" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Either way, we will get the same response with many type variants. This is an abbreviation:

{
    "cardinality": "many",
    "definition": {
        "type": "StructuredDefinition",
        "types": [
            {
                "label": "material_percentage",
                "optional": false
            },
            {
                "label": "material_code",
                "optional": false
            }
        ]
    },
    "label": "material",
    "name": {
        "en-gb": "material"
    },
    "type_variants": [
        {
            "label": "upper_material_clothing",
            "name": {
                "cs": "Materiál vnější látky",
                "da": "Materiale",
                "de": "Material Oberstoff",
                "en": "Outer fabric material",
                "es": "Material exterior",
                "fi": "päällikankaan materiaali",
                "fr": "Composition",
                "it": "Composizione",
                "nl": "Materiaal buitenlaag",
                "no": "Overmateriale",
                "pl": "Materiał",
                "pt": "material do tecido exterior",
                "ru": "",
                "sv": "Material",
                "tr": ""
            }
        },
        ...
    ],
    "usage": "literal"
}

Note that the types field includes material_percentage and material_code. The attribute type material is a complex attribute type which consists of these two attributes.

Both of these component attributes are typical attribute types, and we can request their individual schemas like any other:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/material_percentage" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

From the response we can see the attribute type material_percentage is a decimal:

{
  "label": "material_percentage",
  "name": {
    "en-gb": "material_percentage"
  },
  "type_variants": [],
  "cardinality": "one",
  "definition": {
    "type": "DecimalDefinition"
  },
  "usage": "literal"
}

To request the schema for the other component attribute material_code using httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/material_code" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

The response:

{
  "label": "material_code",
  "name": {
    "en-gb": "material_code"
  },
  "type_variants": [],
  "cardinality": "one",
  "definition": {
    "type": "LocalizedStringDefinition"
  },
  "usage": "reference_by_label"
}

And to request the attributes for material_code with httpie:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/material_code/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

An abbreviated example response:

{
  "items": [
    {
      "label": "li",
      "name": {
        "en": "Linen"
      },
      "value": {
        "localized": {
          "fr": "lin",
          "pt": "linho",
          "cs": "len",
          "it": "lino",
          "nl": "linnen",
          "de": "Leinen",
          "sv": "lin",
          "da": "hør",
          "en": "linen",
          "es": "lino",
          "fi": "pellava",
          "no": "lin",
          "pl": "len"
        }
      }
    },
  ...
  ]
}

This is a valid example entry for material.upper_material_clothing in a product submission JSON:

"material.upper_material_clothing": [
  {
    "material_code": "li",
    "material_percentage": 97.50
  },
  {
    "material_code": "el",
    "material_percentage": 2.50
  }
]

Complex Attribute Example: sustainability certificate

Note

For more information on the sustainability certificate have a look at Sustainability.

Another complex attribute is sustainability certificate. It's composed of five fields:

  • certificate_info
  • certificate_test_institute
  • certificate_approval_number
  • certification_tier
  • product_component

Some are associated with strings, and others are associated with structured values. Some fields are mandatory and others are optional. To get to know the field types and their optionality, you need to query the Merchant Attributes service.

From the Merchant Attributes information (see sections below), it can be deduced that the certificate attribute's value is a json object with the following structure:

{
  "certificate_info": string,
  "product_component": {
    "variant": string,
    "certified_percentage": number
  },
  "certification_tier": string,
  "certificate_test_institute": string,
  "certificate_approval_number": string
}
Click to show an example request body (to Submission Service) with a certificate attribute
{
  "outline": "shirt",
  "product_model": {
    "merchant_product_model_id": "...",
    "product_model_attributes": {},
    "product_configs": [
      {
        "merchant_product_config_id": "...",
        "product_config_attributes": {
          "media": [],
          "certificate": {
            "certificate_info": "home_labels_7848",
            "product_component": {
              "variant": "non_material_variant:full_product",
              "certified_percentage": 100
            },
            "certification_tier": "assembly_factory",
            "certificate_test_institute": "Control Union Certifications B.V.",
            "certificate_approval_number": "CU811380GRS-2021-00000000"
          },
          "description": {},
          "season_code": "",
          "supplier_code": "...",
          "color_code.primary": ""
        },
        "product_simples": []
      }
    ]
  }
}
certificate
Click to see `attribute-types` request for `certificate`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certificate \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types` response for `certificate`
{
  "cardinality": "one",
  "definition": {
    "type": "StructuredDefinition",
    "types": [
      {
        "label": "certificate_info",
        "optional": false
      },
      {
        "label": "certificate_test_institute",
        "optional": true
      },
      {
        "label": "certificate_approval_number",
        "optional": true
      },
       {
        "label": "certification_tier",
        "optional": true
      },
      {
        "label": "product_component",
        "optional": true
      }
    ]
  },
  "label": "certificate",
  "name": {
    "hr": "Održivost",
    "lv": "Ilgtspējība",
    "et": "Jätkusuutlikkus",
    "de": "Nachhaltigkeit",
    "en": "Sustainability",
    "sk": "Udržateľnosť",
    "lt": "Tvarumas",
    "sl": "Trajnostnost"
  },
  "type_variants": [],
  "usage": "literal"
}
certificate.certificate_info:
Click to see `attribute-types` request for `certificate_info`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certificate_info \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types` response for `certificate_info`
{
  "cardinality": "one",
  "definition": {
    "type": "LocalizedStringDefinition"
  },
  "label": "certificate_info",
  "name": {
    "fr": "Développement durable",
    "pt": "Sustentabilidade",
    "cs": "Udržitelnost",
    "it": "Sostenibilità",
    "nl": "Duurzaamheid",
    "de": "Nachhaltigkeit",
    "pl": "Produkt przyjazny dla środowiska"
  },
  "type_variants": [],
  "usage": "reference_by_label"
}

Attribute that certificate_info has definition of LocalizedStringDefinition, and it's usage is reference_by_label. This means that certificate_info can be assigned only certain values. These are returned by the attribute-types/certificate_info request:

Click to see `attribute-types/attributes` request for `certificate_info`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certificate_info/attributes \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types/attributes` response for `certificate_info`
{
  "items": [
    {
      "label": "home_labels_8311",
      "name": {
        "en": "home_labels_8311"
      },
      "value": {
        "localized": {
          "cs": "LENZING™ ECOVERO™",
          "da": "LENZING™ ECOVERO™",
          "de": "LENZING™ ECOVERO™",
          "pl": "LENZING™ ECOVERO™",
          "sk": "LENZING™ ECOVERO™",
          "sl": "LENZING™ ECOVERO™",
          "sv": "LENZING™ ECOVERO™"
        }
      }
    },
    {
      "label": "home_labels_5115",
      "name": {
        "en": "home_labels_5115"
      },
      "value": {
        "localized": {
          "cs": "Fairtrade Cotton",
          "da": "Fairtrade Cotton",
          "de": "Fairtrade Cotton",
          "sl": "Fairtrade Cotton",
          "sv": "Fairtrade Cotton"
        }
      }
    }
  ]
}

For example

    "certificate_info": "home_labels_8312"

Notice that the value for certificate_info is a label that represents a LocalizedStringDefinition.

certificate.certification_tier:

Click to see attribute-types request for certification_tier

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certification_tier \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Click to see `attribute-types` response for `certification_tier`
{
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "label": "certification_tier",
  "name": {
    "en": "Certification tier"
  },
  "type_variants": [],
  "usage": "reference_by_value"
}

Attribute certification_tier has definition of StringDefinition, and its usage is reference_by_value. This means that certification_tier can be assigned only certain values. These are returned by the attribute-types/attributes request:

Click to see `attribute-types/attributes` request for `certification_tier`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certification_tier/attributes \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types/attributes` response for `certification_tier`
{
  "items": [
    {
      "label": "assembly_factory",
      "name": {
        "de": "Assembly factory",
        "en": "Assembly factory"
      },
      "value": {
        "string": "assembly_factory"
      }
    }
  ]
}
certificate.certificate_test_institute:
Click to see `attribute-types` request for `certificate_test_institute`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certificate_test_institute \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types` response for `certificate_test_institute`
{
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "label": "certificate_test_institute",
  "name": {
    "hr": "Ispitivačko/certifikacijsko tijelo",
    "fr": "Institut de contrôle / certifié par",
    "sl": "Ustanova za preskušanje/certifikat izdal",
    "pl": "Instytut / certyfikat wydany przez"
  },
  "type_variants": [],
  "usage": "literal"
}

Attribute certificate_test_institute has definition of StringDefinition, and its usage is literal. This means that any string value could be assigned to that attribute.

certificate.certificate_approval_number:
Click to see `attribute-types` request for `certificate_approval_number`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/certificate_approval_number \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types` response for `certificate_approval_number`
{
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "label": "certificate_approval_number",
  "name": {
    "hr": "Broj certifikata/licence",
    "fr": "Certification / numéro de licence"
  },
  "type_variants": [],
  "usage": "literal"
}

Attribute certificate_approval_number has definition of StringDefinition, and its usage is literal. This means that any string value could be assigned to that attribute.

certificate.product_component:

Click to see attribute-types request for product_component

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/product_component \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Click to see `attribute-types` response for `product_component`
{
  "cardinality": "one",
  "definition": {
    "type": "StructuredDefinition",
    "types": [
      {
        "label": "variant",
        "optional": false
      },
      {
        "label": "certified_percentage",
        "optional": false
      }
    ]
  },
  "label": "product_component",
  "name": {
    "en": "Certified product component"
  },
  "type_variants": [],
  "usage": "literal"
}
certificate.product_component.variant:
Click to see `attribute-types` request for `variant`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/variant \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types` response for `variant`
{
  "cardinality": "one",
  "definition": {
    "type": "StringDefinition"
  },
  "label": "variant",
  "name": {
    "en": "Material or Non-Material variant"
  },
  "type_variants": [],
  "usage": "reference_by_value"
}

Attribute variant has definition of StringDefinition, and its usage is reference_by_value. This means that variant can be assigned only certain values. These are returned by the attribute-types/attributes request:

Click to see `attribute-types/attributes` request for `variant`
http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/variant/attributes \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"
Click to see `attribute-types/attributes` response for `variant`
{
  "items": [
    {
      "label": "decksohle",
      "name": {
        "en-gb": "decksohle"
      },
      "value": {
        "string": "material_variant:decksohle"
      }
    },
    {
      "label": "full_product",
      "name": {
        "en-gb": "full_product"
      },
      "value": {
        "string": "non_material_variant:full_product"
      }
    }
  ]
}

Example:

    "variant": "non_material_variant:full_product"

Note, that for each product outline, only a subset of variants is allowed.

certificate.product_component.certified_percentage:

Click to see attribute-types request for certified_percentage
http\
https://api-sandbox.merchants.zalando.com\
/merchants/$YOUR_MERCHANT_ID/attribute-types/certified_percentage\
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

Click to see `attribute-types` request for certified_percentage
{
  "cardinality": "one",
  "definition": {
    "type": "DecimalDefinition"
  },
  "label": "certified_percentage",
  "name": {
    "en": "Certified percentage"
  },
  "type_variants": [],
  "usage": "literal"
}

Retrieve certificate

The submitted certificate can be retrieved using the PSR API.

Step 5 - Sizes

Sizes Overview

Use the size_group and size_code attributes to set all available sizes of your product.

The product_model size_group attribute specifies which category of size the product belongs to. For example, watches and shoes use different size groups.

The product_simple size_code attribute specifies the actual size of each EAN (such as "size 42" or "XXL"). The available size_code values for your product will depend on what size_group it uses for the product_model.

Both size_group and size_code are complex attribute types which consist of a mandatory size attribute and an optional length attribute. The length attributes are only required for certain products like pants, which often have a waist size and a length. See size_group.length and size_code.length below for more information. Size and length are both reference_by_value, and are therefore take label values.

The basic steps for setting sizes for your submission are:

  1. Get the attributes of the size attribute.
  2. Find the appropriate size group for your product.
  3. Add the corresponding size_group.size value to the product_model tier of your product JSON.
  4. For all simples in your submission JSON, find the appropriate size_code.size value in the size_group you chose and add the appropriate value to the product_simple tier of your JSON.
  5. If necessary, add the size_group.length value to the product_model tier of your product JSON, and size_code.length values to each EAN in the product_simple tiers.

Get the attributes of the size attribute

A key source of information for entering size values is the enumeration of attributes of the size attribute type. To get it with httpie, send the following call:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/size/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN"

This call returns a large schema which defines all available size categories and size options for every available product type. You may wish to write the returned JSON to a file for easier reference, as in this example:

http \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/attribute-types/size/attributes" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN" >> size_attributes.txt
Click to see an example of a small part of the returned JSON
{
  "items": [
    {
      "_meta": {
        "active": true,
        "dimension": {
          "value": "Shoe size",
          "type": "size",
          "name": "Shoes",
          "group": "Female",
          "comment": "Shoes, socks, knee socks, shoe trees",
          "category": "Shoes"
        },
        "sizes": [
          {
            "conversions": [
              {
                "cluster": "eu",
                "raw": "42"
              },
              {
                "cluster": "us",
                "raw": "11"
              }
            ],
            "supplier_size": "42",
            "sort_key": 18
          },
          {
            "conversions": [
              {
                "cluster": "eu",
                "raw": "44.5"
              },
              {
                "cluster": "us",
                "raw": "13"
              }
            ],
            "supplier_size": "44.5",
            "sort_key": 22
          },
          ...
        ]
      },
      "label": "4FE1000E0A",
      "name": {
        "en-gb": "4FE1000E0A"
      },
      "value": {
        "string": "4FE1000E0A"
      }
    },
    {
      "_meta": {
        "active": true,
        "dimension": {
          "category": "Clothing",
          "comment": "Pants, leggings, jeans, ...",
          "group": "Male",
          "name": "Clothing",
          "type": "size",
          "value": "Confection"
        },
        "sizes": [
          {
            "conversions": [
              {
                "cluster": "eu",
                "raw": "M"
              },
              {
                "cluster": "us",
                "raw": "M"
              }
            ],
            "sort_key": 7,
            "supplier_size": "M"
          },
          {
            "conversions": [
              {
                "cluster": "eu",
                "raw": "L"
              },
              {
                "cluster": "us",
                "raw": "L"
              }
            ],
            "sort_key": 9,
            "supplier_size": "L"
          },
          ...
        ]
      },
      "label": "4MU1000E2A",
      "name": {
        "en-gb": "4MU1000E2A"
      },
      "value": {
        "string": "4MU1000E2A"
      }
    },
    ...
  ]
}

This schema enumerates all size types for all size categories of products. Note that some size groups are brand specific.

Json can contain an empty array:

{
  "items": []
}
In this case attribute values are not configured. In case you might need any support, please reach out to partner-care@zalando.de

size_group.size

You must select a size_group for your product before setting the size_codes. The available size_codes options depend on which size_group you use.

First, use the dimension attributes meta-data in the size attributes enumeration to find the right size group for your product. We recommend beginning by searching for key words that describe your product, such as "pant" or "shoe", and look for corresponding values in fields such as dimension.name and dimension.comment.

Unfortunately, different manufacturers use different size chart conventions, so the set of size groups is not systematically organized. As a result, it is important to check the size attributes list carefully. If you believe you have found the right group, check the other remaining options anyway to verify that there is no better match.

Be sure that you select size values, and not length values. Size group enumerations look very similar to length group enumerations, except thedimension.type value is size instead of length, as in this example:

"_meta": {
        "active": true,
        "dimension": {
          "category": "Clothing",
          "comment": "Pants, leggings, jeans, ...",
          "group": "Male",
          "name": "Clothing",
          "type": "size",
          "value": "Confection"
        },
}

Once you have found the best possible match, enter the value of the label attribute of the group as the value of size_group.size in your submission JSON.

Click to see a submission JSON from the example above
 {
    "value": {
        "string": "4FA0AD5U5A"
    },
    "name": {
        "en-gb": "4FA0AD5U5A"
    },
    "label": "4FA0AD5U5A",
    "_meta": {
      "sizes": [
          {
            "supplier_size": "2",
            "sort_key": 10
          },
          {
            "supplier_size": "3",
            "sort_key": 11
          },
          {
            "supplier_size": "4",
            "sort_key": 12
          },
          ...
      ],
      "dimension": {
          "value": "Confection",
          "type": "size",
          "name": "Sport",
          "group": "Female",
          "comment": "",
          "category": "Sport"
      },
      "descriptions": {
        "en": "Sports, Women, sandals, adidas Performance, UK[2-10]"
      },
      "brand_code": "AD5",
      "active": true
    }
},

Enter the following label value to the product_model tier in your submission JSON:

"size_group": {
  "size": "4FA0AD5U5A"
}

size_code.size

Now that you have identified the size_group, you can find the corresponding size codes. Add the value for the supplier_size field to the corresponding product_simple in your product submission JSON as shown below.

"size_codes": {
  "size": "2"
}

For example, suppose you have a size 2 sandals with the EAN 9780679762881. You would add the following definition to your submission JSON:

"product_simples": [
  {
    "merchant_product_simple_id": "sandals-1105AA",
    "product_simple_attributes": {
      "ean": "9780679762881",
      "size_codes": {
        "size": "2"
      }
    }
  },

Repeat this step for all product_simples in your submission.

size_group.length and size_code.length

Some products have more than one size code per simple. Many pants, for example, have a waist size and a length.

For these cases, there are additional size_group.length and size_code.length attribute types.

The process for entering the correct values for the size_group.length and size_code.length attribute types is basically the same as the process for finding the size attributes described above, except you will use length groups instead of size groups.

To begin, find the appropriate length group that matches your size group. Be sure that you select length values, and not size values. Length group enumerations are identical to size group enumerations, except the value of dimension.type is length instead of size:

"dimension": {
  "value": "Length",
  "type": "length",
  "name": "Pants/ trousers",
  "group": "Unisex",
  "comment": "Pants, leggings, jeans, sports pants ...",
  "category": "Clothing"
}

Once you have selected the best length group, enter the value of the label attribute of the group as the value of size_group.size in your submission JSON.

Here is an example product_model entry:

"size_group": {
  "size": "4MU1000E2A",
  "length": "5AAU000012"
}

For each product_simple, add the appropriate supplier_size value from the size enumeration as the value of size_codes.length.

Here is an example product_simple entry:

"size_codes": {
  "size": "42",
  "length": "52"
}

Size Attributes Reference Chart

Value Where it is defined in the size attributes enumeration
size_group.size For any size group where dimension.type = size, the value of label
size_code.size For any size group where dimension.type = size, the value of supplier_size
size_group.length For any size group where dimension.type = length, the value of label
size_code.length For any size group where dimension.type = length, the value of supplier_size

Step 6 - Images

Each product in the Zalando Product Catalog must have an accompanying set of required images, and each product can have only one set of images. Different merchants may not use different sets of images for the same product.

When submitting a new product to Zalando, you must submit the required set of images. This submission process consists of the following steps:

  1. Prepare images meeting Zalando requirements,
  2. Host the image files at any publicly-available URLs, and
  3. In the product submission JSON, specify the image URLs as an array in the mandatory Config attribute type media.

During product submission validation, we will validate and download the images from the provided URLs.

Image files cannot currently be uploaded directly to Zalando.

Image Requirements

In order to maintain a high-quality and consistent presentation, we have technical requirements that any product image must meet:

Requirement Value
Minimum size 762 * 1100 pixels
Recommended size 1524 * 2200 pixels
Maximum size 6000 * 9000 pixels
Image type JPEG
Color mode RGB
Format Upright

For detailed information on more image requirements and business rules, see our Image and Content Guides in Zalando Partner University.

Host image files at any public URL

You may host your images at any public location (e.g. a public Dropbox).

Each image must be hosted at a unique URL. Do not enclose images in an archive.

Note

Do not remove images while the article is in In Review or Rejected ASO status.

Add image URL to the media field

The mandatory product_config attribute type media is a complex attribute type that consists of the attributes media_path and media_sort_key.

The media_path value takes a single valid URL, and the media_sort_key value takes a single integer that will be used to define the sort order of the image.

The following example illustrates a valid media field in a product submission JSON:

"media": [
  {
    "media_path": "https://hosting_of_your_choice/media/7b077fc4-fde3-47d4-8b25-97af8792/pic-1.jpg",
    "media_sort_key": 1
  },
  {
    "media_path": "https://hosting_of_your_choice/media/7b077fc4-fde3-47d4-8b25-97af8792/pic-2.jpg",
    "media_sort_key": 2
  }
]

Step 7 - Submission and Validation

Once you have completed constructing the submission JSON, use the Product Submissions API to submit it.

It is important that you add all product_config and product_simple tiers in a single submission containing all size and color combinations.

In case you wish to sell a product model that already exists, but it does not contain product simples that you need, you will need to resubmit the whole product structure with the additional simples. See Products FAQ for assistance.

Click to see an example of a complete and valid product submission
{
  "outline":"sandals",
  "product_model":{
    "merchant_product_model_id":"MODEL_ID_123",
    "product_model_attributes":{
      "name":"AIR FORCE SANDALS 1 '07 LV8 UTILITY",
      "brand_code":"ns1",
      "size_group":{
        "size":"4MU1000E2A"
      },
      "target_genders":[
        "target_gender_male",
        "target_gender_female"
      ],
      "target_age_groups":[
        "target_age_group_adult"
      ]
    },
    "product_configs":[
      {
        "merchant_product_config_id":"7b077fc4-fde3-47d4-8b25-97af8793",
        "product_config_attributes":{
          "color_code.primary":"608",
          "description":{
            "en":"Nice sandals"
          },
          "material.upper_material_clothing":[
            {
              "material_code":"li",
              "material_percentage":87.5
            },
            {
              "material_code":"el",
              "material_percentage":12.5
            }
          ],
          "media":[
            {
              "media_path":"https://hosting_of_your_choice/media/7b077fc4-fde3-47d4-8b25-97af8793/pic-1.jpg",
              "media_sort_key":1
            },
            {
              "media_path":"https://hosting_of_your_choice/media/7b077fc4-fde3-47d4-8b25-97af8793/pic-2.jpg",
              "media_sort_key":2
            }
          ],
          "season_code":"fs20",
          "supplier_color":"mint"
        },
        "product_simples":[
          {
            "merchant_product_simple_id":"mint-shoes-3326CC",
            "product_simple_attributes":{
              "ean":"9813752182012",
              "size_codes":{
                "size":"44.5"
              }
            }
          }
        ]
      }
    ]
  }
}

To submit a JSON file, navigate to the directory where it exists and use the Product Submissions API. This httpie command submits the file product.json in the local directory:

http POST \
https://api-sandbox.merchants.zalando.com/merchants/$YOUR_MERCHANT_ID/product-submissions" \
"Authorization:Bearer $YOUR_ACCESS_TOKEN" < product.json

Submission Validation and Product Status Reports

While handling a submission request, we perform the first validation steps to verify that the provided JSON object is well-formed and contains values for all mandatory attributes.

If you receive a 400 Bad Request response, it means that your JSON does not pass our initial validation. For example, if you neglect to specify a value for the mandatory name attribute, you will receive:

{
  "title": "Bad Request",
  "flow_id": "rihm6p+EBC3G0Bxc",
  "detail": "Wrong body format",
  "contact": "zdirect-tech-support@zalando.de",
  "code": 400,
  "body_errors": [
    {
      "path": "/product_model/product_model_attributes/name",
      "expected": "String",
      "actual": "Undefined"
    }
  ]
}

From this response, entries in body_errors explain why the submission was not accepted. You need to address them, adjust the submission and retry.

If you receive a 422 Unprocessable Entity response, then your grouping of Model / Config / Simple is not the same as that of existing products in the Zalando Catalog. Please reach out to our Support team with X-Flow-Id header and the response body. For contact information, see Support.

If you obtain a 200 OK response, it means your submission has passed initial validation and was received, but it does not mean that the product will be created yet. The Submission may later be rejected and assigned PS_ERR errors, which can be inspected in ZDirect Articles.

Product Submission Validation (Jan 2025 release)

From mid-January 2025, the Submission API will be updated. Although the overall behaviour will remain same, there will be bug fixes, and improvement to the error messages. There will also be warnings that will indicate if there is a problem with optional attributes that leads them to be ignored from the submission, or that a problem that will lead to PS_ERR errors.

In the response, in addition to body_errors, body_warnings may be present.

Please refer to the following documentation for detailed information: Submissions API Release 2025: Validation

Step 8: Resubmit the product, if necessary

Once submitted, your product will undergo additional validations. It can still be rejected and it will only be added to the Zalando Catalog when all validation steps succeed. Use the Product Status Report (PSR) to track the status of any submitted product along with information on any issues that may be detected with further validations. PSR is also available through the zDirect UI.

Once the product is added to the Zalando Catalog, you may use the Prices API to set prices, and the Stocks API to set available stock.

If your submission failed further validations and was rejected, you may correct any errors and repeat the submission process to re-submit it.

Warning

We not keep a history of your submission attempts. The complete submission object must be sent again and only data included in the last successful request will be sent for further validation.

Additional Resources

Contact Support