Product Onboarding API Best Practices
This page covers media submission guidelines and Sandbox behavior for the Product Onboarding API. For general information on how to use the API, see Product Onboarding API Overview.
Submitting media
Various flavors of media can be provided:
- General Product Safety Regulation files (GPSR)
- Images
Publicly-accessible media links should be provided. Please ensure:
- No authorization required for downloading from these provided links
- No significant delays for fetching binary over network occur during download attempts
- New media assets submitted under new links
- Supported file formats: png, jpeg, jpg, pdf
- File size limits: up to 20 Mb for images and up to 50 Mb for PDF-files
The whole request will be rejected with 400 Bad Request error if either of the following conditions met:
- url missing for image or GPSR media attribute
- sort_order missing for image
- two or more identical URLs provided across the whole submission
Sandbox Behavior
The Sandbox is a dedicated environment where you can validate your integration with the Product Onboarding API before sending real product data to production. In the Sandbox:
- Your requests go through the same API schema validation and OAuth2 token authorization as production.
- Your requests are not validated against real product data rules (no duplicate detection, no material/logistics/compliance checks, no GTIN lookups). Instead, the Sandbox returns predictable, controllable responses so you can build and test your error-handling logic.
- No data is persisted and nothing is sent downstream - you can submit the same request as many times as you like.
How to Trigger a Success or a Failure (Sync Mode)
This mechanism applies in synchronous mode, where the response
reflects the processing result immediately. In asynchronous mode, the Sandbox returns a submission_id the same way
production does, but the submission is never actually processed.
The Sandbox inspects the values you send in your request. This gives you full control over what response you get back, without needing any special headers or configuration:
- Submit normal-looking values -> you get back a
SUCCESSresponse. - Include the word
INVALID(case-insensitive) anywhere in the value of any attribute, at any level of the payload (model, config, or simple) -> that attribute is reported back as a validation error, and the overall response becomes aFAILURE.
You can combine this with any number of attributes, at any tier, to simulate single or multiple validation errors in one request.
Example 1 - Success
Request:
curl -X POST https://api-sandbox.merchants.zalando.com/partners/{business_partner_id}/products \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-H "X-Flow-ID: my-test-flow-001" \
-H "X-Api-Mode: sync" \
-d '{
"product_model": {
"product_model_attributes": {
"supplier_article_name": "Sample Product"
},
"product_configs": [
{
"product_config_attributes": {
"supplier_color": "Black",
"pattern": "plain"
},
"product_simples": [
{
"product_simple_attributes": {
"gtin": "5233232112240"
}
}
]
}
]
}
}'
Response - 200 OK:
{
"title": "SUCCESS",
"status": 200,
"detail": "The product data has been successfully processed.",
"flow_id": "my-test-flow-001",
"body_errors": null
}
Example 2 - Single Attribute Failure
Change one attribute's value to contain INVALID:
Request:
curl -X POST https://api-sandbox.merchants.zalando.com/partners/{business_partner_id}/products \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-H "X-Flow-ID: my-test-flow-002" \
-H "X-Api-Mode: sync" \
-d '{
"product_model": {
"product_model_attributes": {
"supplier_article_name": "Sample Product"
},
"product_configs": [
{
"product_config_attributes": {
"supplier_color": "Black",
"certificate": {
"certificate_info": "Test INVALID Info"
}
},
"product_simples": [
{
"product_simple_attributes": {
"gtin": "5233232112240"
}
}
]
}
]
}
}'
Response - 400 Bad Request:
{
"title": "FAILURE",
"status": 400,
"detail": "The product data haven't been updated.",
"flow_id": "my-test-flow-002",
"body_errors": [
{
"path": "product_model/product_configs/0/product_config_attributes/certificate",
"tier": "config",
"attribute": "certificate",
"message": "Invalid value detected: '{certificate_info=Test INVALID Info}'",
"error_code": "PSERR_309"
}
]
}
Example 3 - Multiple Failures Across Different Levels
You can put INVALID in attributes at the model, config, and simple level in a single request to get multiple errors
back at once:
Request:
curl -X POST https://api-sandbox.merchants.zalando.com/partners/{business_partner_id}/products \
-H "Authorization: Bearer <your-token>" \
-H "Content-Type: application/json" \
-H "X-Flow-ID: my-test-flow-003" \
-H "X-Api-Mode: sync" \
-d '{
"product_model": {
"product_model_attributes": {
"supplier_article_name": "Product INVALID Name"
},
"product_configs": [
{
"product_config_attributes": {
"supplier_color": "Black",
"pattern": "INVALID_PATTERN",
"material.upper_material_back": [
{
"material_percentage": 50,
"material_code": "INVALID Material"
}
]
},
"product_simples": [
{
"product_simple_attributes": {
"gtin": "5233232112240",
"eu_address": "Address INVALID EU"
}
}
]
}
]
}
}'
Response - 400 Bad Request:
{
"title": "FAILURE",
"status": 400,
"detail": "The product data haven't been updated.",
"flow_id": "my-test-flow-003",
"body_errors": [
{
"path": "product_model/product_model_attributes/supplier_article_name",
"tier": "model",
"attribute": "supplier_article_name",
"message": "Invalid value detected: 'Product INVALID Name'",
"error_code": "PSERR_309"
},
{
"path": "product_model/product_configs/0/product_config_attributes/pattern",
"tier": "config",
"attribute": "pattern",
"message": "Invalid value detected: 'INVALID_PATTERN'",
"error_code": "PSERR_309"
},
{
"path": "product_model/product_configs/0/product_config_attributes/material.upper_material_back",
"tier": "config",
"attribute": "material.upper_material_back",
"message": "Invalid value detected: '[{material_percentage=50.0, material_code=INVALID Material}]'",
"error_code": "PSERR_309"
},
{
"path": "product_model/product_configs/0/product_simples/0/product_simple_attributes/eu_address",
"tier": "simple",
"attribute": "eu_address",
"message": "Invalid value detected: 'Address INVALID EU'",
"error_code": "PSERR_309"
}
]
}