A Brand represents the manufacturer or commercial brand associated with products in the catalog. Brands are used for catalog organization, filtering, and SEO presentation.
Fixed fields: id
Default fields: name, internal_id, url
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of brands with optional filtering and ordering.
| brand_ids | Array of integers Filter brands by a comma-separated list of brand IDs. Exact match on |
| internal_ids | Array of strings Filter brands by a comma-separated list of brand internal IDs. Exact match on |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| slug | Array of strings Filter brands by a comma-separated list of slugs. Max 200 slugs. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- {
- "id": 2,
- "name": "Marca de Ejemplo",
- "internal_id": "BRAND-001",
- "translations": {
}
}
]
]
}Create a new brand with the provided details.
| name required | string Name of the brand. |
| internal_id | string or null Internal ID for the brand. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| slug | string^[-a-zA-Z0-9_]+$ URL-friendly slug for the brand. If not provided, it will be automatically generated from the name. Updating it changes the URL and may impact SEO (links and indexed pages). Cache invalidation or page refresh may be required for the change to take effect immediately. |
| delivery_time_in_stock | integer >= 0 Estimated delivery time in days when the product is in stock. |
| delivery_time_out_of_stock | integer >= 0 Estimated delivery time in days when the product is out of stock. |
| image_url | string or null <uri> URL of the brand logo image. If provided, the image will be downloaded and saved. The timeout for downloading the image is set to 5 seconds. |
required | Array of objects (BrandTranslation) |
{- "name": "Marca de Ejemplo",
- "internal_id": "BRAND-001",
- "delivery_time_in_stock": 1,
- "delivery_time_out_of_stock": 3,
- "translations": {
- "es-ES": {
- "description": "Descripción de la marca de ejemplo en español.",
- "body_html": "<p>Descripción de la marca de ejemplo en formato HTML.</p>",
- "long_name": "Marca de Ejemplo - Productos Ecológicos",
- "meta_title": "Marca de Ejemplo · Moda y Estilo de Vida",
- "meta_description": "Descubre la Marca de Ejemplo, la elección número 1 para productos ecológicos.",
}, - "en-GB": {
- "description": "This is an example brand.",
- "body_html": "<p>Example brand description in HTML format.</p>",
}, - "fr-FR": {
- "description": "Ceci est une marque d'exemple.",
- "body_html": "<p>Description de la marque d'exemple en format HTML.</p>",
- "size_guide_file": {
- "name": "guide_des_tailles.pdf",
}
}
}
}[- {
- "id": 2,
- "name": "Marca de Ejemplo",
- "internal_id": "BRAND-001",
- "translations": {
}
}
]Update an existing brand's details.
| id required | integer |
| name | string Name of the brand. |
| internal_id | string or null Internal ID for the brand. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| slug | string^[-a-zA-Z0-9_]+$ URL-friendly slug for the brand. If not provided, it will be automatically generated from the name. Updating it changes the URL and may impact SEO (links and indexed pages). Cache invalidation or page refresh may be required for the change to take effect immediately. |
| delivery_time_in_stock | integer >= 0 Estimated delivery time in days when the product is in stock. |
| delivery_time_out_of_stock | integer >= 0 Estimated delivery time in days when the product is out of stock. |
| image_url | string or null <uri> URL of the brand logo image. If provided, the image will be downloaded and saved. The timeout for downloading the image is set to 5 seconds. |
Array of objects (BrandTranslation) |
{- "name": "Other Brand Name",
- "internal_id": "new_internal_id",
- "translations": {
- "en-GB": {
- "description": "Updated description for the example brand."
}, - "es-ES": {
- "description": "Descripción actualizada en español."
}
}
}{- "id": 2,
- "name": "Other Brand Name",
- "internal_id": "new_internal_id",
- "translations": {
}
}A Category represents a hierarchical grouping of products in the catalog. Categories are used for navigation (category pages), filtering, and SEO presentation.
Fixed fields: id
Default fields: internal_id, name, url
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of categories with optional filtering and ordering.
| category_ids | Array of integers Filter categories by a comma-separated list of category IDs. Exact match on |
| internal_ids | Array of strings Filter categories by a comma-separated list of category internal IDs. Exact match on |
| is_root_folder | boolean Filter categories that are root folders (i.e., have no parent). |
| page | integer A page number within the paginated result set. |
| parent_id | number Filter categories by parent category ID. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| slug | string Filter categories by a comma-separated list of slugs. Max 200 slugs. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| status | string Enum: "published" "unpublished" Filter categories by publication status.
|
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- {
- "id": 1,
- "internal_id": "CAT-001",
- "translations": {
}
}
]
}Create a new category with the provided details.
| internal_id | string or null Internal ID for the category. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| image_url | string or null <uri> URL of the category image. If provided, the image will be downloaded and saved. The timeout for downloading the image is set to 5 seconds. |
| parent_id | integer or null ID of the parent category, if any. Null if this is a top-level category. |
| status required | string Enum: "published" "unpublished" Status of the object: 'published' or 'unpublished'.
|
object Merchant category mappings (e.g., Google taxonomy). | |
required | Array of objects (CategoryTranslation) |
{- "internal_id": "CAT-002",
- "parent_id": 23,
- "status": "published",
- "merchant_categories": {
- "google": {
- "id": "123"
}
}, - "translations": {
- "en-GB": {
- "name": "New Category",
- "description": "A newly created category",
- "body_html": "<p>New category description in HTML format.</p>",
- "long_name": "New Category - Ecologically Friendly Goods",
- "meta_title": "New Category · Fashion and Lifestyle",
- "meta_description": "Discover New Category, the #1 choice for eco-friendly products."
}, - "es-ES": {
- "name": "Nueva Categoría",
- "description": "Una categoría recién creada",
- "body_html": "<p>Descripción de la nueva categoría en formato HTML.</p>",
- "long_name": "Nueva Categoría - Productos Ecológicos",
- "meta_title": "Nueva Categoría · Moda y Estilo de Vida",
- "meta_description": "Descubre Nueva Categoría, la elección número 1 para productos ecológicos."
}
}
}{- "id": 2,
- "internal_id": "CAT-002",
- "translations": {
}
}Update an existing category's details.
| id required | integer |
| internal_id | string or null Internal ID for the category. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| image_url | string or null <uri> URL of the category image. If provided, the image will be downloaded and saved. The timeout for downloading the image is set to 5 seconds. |
| parent_id | integer or null ID of the parent category, if any. Null if this is a top-level category. |
| status | string Enum: "published" "unpublished" Status of the object: 'published' or 'unpublished'.
|
object Merchant category mappings (e.g., Google taxonomy). | |
Array of objects (CategoryTranslation) |
{- "status": "published",
- "merchant_categories": {
- "google": {
- "id": "456"
}
}, - "translations": {
- "en-GB": {
- "name": "Updated Electronics"
}, - "es-ES": {
- "name": "Electrónica Actualizada"
}
}
}{- "id": 1,
- "internal_id": "CAT-001",
- "translations": {
}
}A Contact is created when a person provides identifying information through any of the following actions:
A contact can be a customer, a subscriber, or both.
Other considerations:
id field. Additionally, the email and internal_id fields are also unique and cannot be duplicated across contacts.id.subscribed or unsubscribed, indicating their marketing preference. Only contacts with a marketing state of subscribed are eligible to receive marketing communications.Fixed fields: id
Default fields: internal_id, is_active, email, first_name, last_name, full_name, phone, preferred_locale
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of contacts with optional filtering and ordering.
The view parameter is required to define the subset of contacts to return (e.g. customers, subscribers).
| contact_ids | Array of integers Filter contacts by a comma-separated list of contact IDs. Exact match on |
| created_at_from | string <date-time> Filter contacts created from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| created_at_to | string <date-time> Filter contacts created up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| customer_type | string Merchant-defined customer (contact) classification (e.g. professional, individual, sector). Selected during registration and editable by the customer. Exact case-sensitive match on |
Array of strings Filter contacts by a comma-separated list of emails. Max 200 emails. Exact match case-insensitive on | |
| internal_ids | Array of strings Filter contacts by a comma-separated list of contact internal IDs. Exact match on |
| is_active | boolean Filter customers (contacts) by active status. |
| is_agreed_payment_enabled | boolean Filters customers (contacts) with agreed payment enabled. |
| is_b2b | boolean Filters B2B customers (contacts). |
| is_customer | boolean Filter contacts that have made a purchase or completed a registration. |
| last_login_at_from | string <date-time> Filter customers (contacts) whose last login was from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| last_login_at_to | string <date-time> Filter customers (contacts) whose last login was up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| mkt_state | string Enum: "not_subscribed" "subscribed" "unsubscribed" Filter customers (subscribers) by subscription state.
|
| orders_count_min | number Filter customers (contacts) with a minimum number of created orders. |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| view required | string Enum: "customers" "subscribers" Which subset of contacts to return. Must be |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- {
- "id": 1,
- "internal_id": "CONT-0001",
- "is_active": true,
- "email": "contact@example.com",
- "first_name": "Jane",
- "last_name": "Doe",
- "full_name": "Jane Doe",
- "phone": "600123456",
- "preferred_locale": "en-GB"
}
]
}Retrieve detailed information about a specific contact by its ID.
| id required | integer |
{- "id": 1,
- "internal_id": "CONT-0001",
- "is_active": true,
- "email": "contact@example.com",
- "first_name": "Jane",
- "last_name": "Doe",
- "full_name": "Jane Doe",
- "phone": "600123456",
- "preferred_locale": "en-GB"
}A Job represents an asynchronous background task created by OpenTiendas to process heavy API operations without blocking the original request or affecting store performance.
Jobs are commonly created by bulk API operations, such as
products_bulk_upsert or variants_bulk_update. When
one of these operations is accepted, the API returns 202 Accepted
together with a job_id. This initial response confirms that the
job has been created and queued for processing. The final result is determined
later, when the job is processed.
External integrations can use jobs to inspect the status, result, and processing logs of large operations. They can also subscribe to job webhooks to be notified automatically when a job reaches a final state, avoiding periodic polling.
A completed job may still contain errors. Use
completed_with_errors to detect jobs where the background task
finished but some records could not be processed successfully. Use the Job Logs
endpoint to inspect the affected records and validation details.
Other considerations:
Fixed fields: id
Default fields: type, status, created_at, started_at, finished_at, summary
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of log entries for a specific job, with optional filtering and ordering. Use this endpoint to inspect processing information, warnings, and errors generated during job execution.
Jobs and their logs are retained for 5 days after creation when completed successfully, and for 30 days when failed or completed with errors. See Job Status Values for more information. After the retention period expires, they are automatically deleted.
Each log entry includes a severity value to indicate whether it is informational, a warning, or an error that affected processing.
| Value | Description |
|---|---|
INFO |
Informational messages about job processing progress. |
WARNING |
Indications of potential issues that did not prevent record processing. |
ERROR |
Indications of issues that caused record processing to fail. |
Each log entry includes a code to identify the specific type of issue detected during processing.
| Code | Description |
|---|---|
AMBIGUOUS_MATCH |
More than one record matches the provided identifier. |
INVALID_FIELD_VALUE |
A field has an invalid value. Affected field may be included in affected_fields. |
INVALID_IDENTIFIER |
The identifier used to match the resource is missing or invalid. |
MISSING_REQUIRED_FIELD |
A required field is missing. |
NOT_FOUND |
No existing record was found for the provided identifier. |
OTHER |
An unexpected error occurred during processing. |
| job_id required | string <uuid> |
| code | string or null Enum: "AMBIGUOUS_MATCH" "INVALID_FIELD_VALUE" "INVALID_IDENTIFIER" "MISSING_REQUIRED_FIELD" "NOT_FOUND" "OTHER" Filter log entries by log code. See values and descriptions.
|
| created_at_from | string <date-time> Filter log entries created from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| created_at_to | string <date-time> Filter log entries created up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 500 Default: 100 Number of results to return per page. |
| severity | Array of strings Items Enum: "ERROR" "INFO" "WARNING" Filter log entries by severity. See values and descriptions.
|
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- [
- {
- "id": 1,
- "created_at": "2026-04-29T10:52:44Z",
- "severity": "INFO",
- "code": null,
- "message": "Creating chunks of 200 for payload of size 3",
- "identifiers": null,
- "affected_fields": null
}, - {
- "id": 2,
- "created_at": "2026-04-29T10:52:44Z",
- "severity": "ERROR",
- "code": "INVALID_FIELD_VALUE",
- "message": "Variant must match the existing variant for simple products.",
- "identifiers": {
- "product": "{'internal_id': 'prod-123'}",
- "variant": "{'internal_id': 'var-456'}"
}, - "affected_fields": [
- "variants.internal_id"
]
}, - {
- "id": 3,
- "created_at": "2026-04-29T10:52:44Z",
- "severity": "INFO",
- "code": null,
- "message": "Bulk upsert job completed: 3 total products, 3 products processed, 1 products failed.",
- "identifiers": null,
- "affected_fields": null
}
]
]
]
}Retrieve detailed information about a specific job by its ID.
| Value | Description |
|---|---|
pending | Job is waiting to be processed. |
running | Job is currently being processed. |
done | Job has been completed and all records were processed successfully. |
done_with_errors | Job has been completed but some records could not be processed successfully. |
failed | Job has failed and no records were processed successfully. |
| id required | string <uuid> |
{- "id": "0d1e1658-98c7-470b-a515-bd523cff01f7",
- "type": "bulk_update_variants",
- "status": "completed_with_errors",
- "created_at": "2026-05-13T18:09:09Z",
- "started_at": "2026-05-13T18:18:43Z",
- "finished_at": "2026-05-13T18:19:52Z",
- "summary": {
- "total_records": 2272,
- "processed_records": 2272,
- "succeeded_records": 2218,
- "failed_records": 54,
- "log_info_count": 11,
- "log_warning_count": 2,
- "log_error_count": 63
}
}An Order represents a purchase attempt created when a customer proceeds to the payment step during checkout. It records the items the customer intends to buy together with the commercial and operational information associated with that transaction. Because an order is created at the payment stage while going through the entire checkout process, a customer may generate multiple orders if the checkout process is abandoned and started again.
An order is a transactional snapshot created at that moment. The items, prices, taxes, and totals stored in the order reflect the exact state of the transaction at the time it was created and are not affected by later changes to products, variants, or pricing. Each order contains one or more order items referencing the variants selected by the customer, together with the quantities and commercial conditions applied. It also includes customer information, billing and shipping addresses, payment data, shipping details, and order totals.
Totals are always expressed in the canonical shop currency (ie. EUR).
Fixed fields: id
Default fields: created_at, payment_status, warehouse_release_status, fulfillment_status, delivery_method, locale, payment_method, payment_gateway, paid_at, fulfilled_at, canceled_at, total, shipping, fees, email
Nested objects: customer
No nested objects are included by default. Use the includes query parameter to include nested objects in the response.
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of orders with optional filtering and ordering.
| created_at_from | string <date-time> Filter orders created from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| created_at_to | string <date-time> Filter orders created up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| delivery_method | string (Shipping method) Enum: "shipment" "store_pick_up" Filter orders by delivery method.
|
| fulfilled_at_from | string <date-time> Filter orders fulfilled from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| fulfilled_at_to | string <date-time> Filter orders fulfilled up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| fulfillment_status | string (Delivery Status) Enum: "fulfilled" "partially_fulfilled" "unfulfilled" Filter orders by fulfillment status.
|
| is_canceled | boolean Filter orders by cancellation status. Set to true to get canceled orders, false to get non-canceled orders. |
| order_ids | Array of integers Filter orders by a comma-separated list of order IDs. Exact match on |
| page | integer A page number within the paginated result set. |
| paid_at_from | string <date-time> Filter orders paid from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| paid_at_to | string <date-time> Filter orders paid up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| payment_status | string Enum: "paid" "unpaid" Filter orders by payment status.
|
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| warehouse_release_status | string (State in the warehouse) Enum: "not_released" "partially_released" "released" Filter orders by warehouse release status.
|
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- {
- "id": 1267,
- "payment_status": "paid",
- "warehouse_release_status": "released",
- "fulfillment_status": "fulfilled",
- "created_at": "2026-03-18T10:15:22Z",
- "paid_at": "2026-03-18T10:20:00Z",
- "fulfilled_at": "2026-03-19T15:00:00Z",
- "canceled_at": null,
- "delivery_method": "shipment",
- "locale": "es-ES",
- "payment_method": "card",
- "payment_gateway": "stripe",
- "total": {
- "gross": {
- "amount": "120.00",
- "currency": "EUR"
}, - "net": {
- "amount": "99.17",
- "currency": "EUR"
}, - "tax": {
- "amount": "20.83",
- "currency": "EUR"
}
}, - "shipping": {
- "gross": {
- "amount": "5.00",
- "currency": "EUR"
}, - "net": {
- "amount": "4.13",
- "currency": "EUR"
}, - "tax": {
- "amount": "0.87",
- "currency": "EUR"
}
}, - "fees": {
- "gross": {
- "amount": "2.00",
- "currency": "EUR"
}, - "net": {
- "amount": "1.65",
- "currency": "EUR"
}, - "tax": {
- "amount": "0.35",
- "currency": "EUR"
}
}, - "email": "john.smith@example.com"
}
]
}Retrieve detailed information about a specific order by its ID.
| id required | integer |
{- "id": 1267,
- "payment_status": "paid",
- "warehouse_release_status": "released",
- "fulfillment_status": "fulfilled",
- "created_at": "2026-03-18T10:15:22Z",
- "paid_at": "2026-03-18T10:20:00Z",
- "fulfilled_at": "2026-03-19T15:00:00Z",
- "canceled_at": null,
- "delivery_method": "shipment",
- "locale": "es-ES",
- "payment_method": "card",
- "payment_gateway": "stripe",
- "total": {
- "gross": {
- "amount": "120.00",
- "currency": "EUR"
}, - "net": {
- "amount": "99.17",
- "currency": "EUR"
}, - "tax": {
- "amount": "20.83",
- "currency": "EUR"
}
}, - "shipping": {
- "gross": {
- "amount": "5.00",
- "currency": "EUR"
}, - "net": {
- "amount": "4.13",
- "currency": "EUR"
}, - "tax": {
- "amount": "0.87",
- "currency": "EUR"
}
}, - "fees": {
- "gross": {
- "amount": "2.00",
- "currency": "EUR"
}, - "net": {
- "amount": "1.65",
- "currency": "EUR"
}, - "tax": {
- "amount": "0.35",
- "currency": "EUR"
}
}, - "email": "john.smith@example.com"
}A Price List defines customer-specific prices, discounts and purchase conditions for products. Price lists can include: fixed prices for variants, percentage discounts, quantity-based pricing rules and minimum order requirements.
Important considerations:
Pricing priority:
If a product belongs to multiple categories, the main product category is used for category discount calculation.
Fixed fields: id
Default fields: internal_id, is_active, minimum_order_amount, customers_count, variant_prices_count, global_discount
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of price lists with optional filtering.
| internal_ids | Array of strings Filter price lists by a comma-separated list of price list internal IDs. Exact match on |
| is_active | boolean Filter price lists by active status. |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| price_list_ids | Array of integers Filter price lists by a comma-separated list of price list IDs. Exact match on |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- {
- "id": 3,
- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": null,
- "customers_count": 74,
- "variant_prices_count": 1942,
- "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- {
- "id": 1,
- "internal_id": "CAT-001",
}
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- {
- "id": 1,
- "name": "Sample Brand",
- "internal_id": "BRAND-001",
}
], - "discount": "15.00"
}
]
}
]
}Creates a new price list.
This endpoint only creates the price list configuration. Fixed prices by product must be managed separately.
| internal_id required | string <= 100 characters Merchant-defined identifier used to manage the price list through imports, exports and the API. |
| is_active required | boolean Indicates whether the price list is active. |
object (Money) Minimum order amount required for customers using this custom price list. | |
| global_discount required | string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$ Global discount percentage applied by the custom price list when applicable. Expressed as a percentage value. |
required | Array of objects (CategoriesPriceList) List of category discount rules configured in this custom price list. Each rule applies the specified discount percentage to all included categories. |
required | Array of objects (BrandsPriceList) List of brand discount rules configured in this custom price list. Each rule applies the specified discount percentage to all included brands. |
{- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": {
- "amount": "100.00",
- "currency": "EUR"
}, - "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- 23
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- 1,
- 3
], - "discount": "15.00"
}
]
}{- "id": 3,
- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": {
- "amount": "100.00",
- "currency": "EUR"
}, - "customers_count": 74,
- "variant_prices_count": 1942,
- "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- {
- "id": 23,
- "internal_id": "CAT-023",
- "translations": {
}
}
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- {
- "id": 1,
- "name": "Sample Brand",
- "internal_id": "BRAND-001",
}, - {
- "id": 3,
- "name": "Another Brand",
- "internal_id": "BRAND-003",
}
], - "discount": "15.00"
}
]
}Returns a single price list.
This endpoint does not return fixed prices by variant.
| id required | integer |
{- "id": 3,
- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": null,
- "customers_count": 74,
- "variant_prices_count": 1942,
- "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- {
- "id": 1,
- "internal_id": "CAT-001",
}
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- {
- "id": 1,
- "name": "Sample Brand",
- "internal_id": "BRAND-001",
}
], - "discount": "15.00"
}
]
}Updates an existing price list.
This endpoint only updates the price list configuration. It does not create, update or delete fixed prices by product.
| id required | integer |
| internal_id | string <= 100 characters Merchant-defined identifier used to manage the price list through imports, exports and the API. |
| is_active | boolean Indicates whether the price list is active. |
object (Money) Minimum order amount required for customers using this custom price list. | |
| global_discount | string <decimal> ^-?\d{0,3}(?:\.\d{0,2})?$ Global discount percentage applied by the custom price list when applicable. Expressed as a percentage value. |
Array of objects (CategoriesPriceList) List of category discount rules configured in this custom price list. Each rule applies the specified discount percentage to all included categories. | |
Array of objects (BrandsPriceList) List of brand discount rules configured in this custom price list. Each rule applies the specified discount percentage to all included brands. |
{- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": {
- "amount": "100.00",
- "currency": "EUR"
}, - "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- 23
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- 1,
- 3
], - "discount": "15.00"
}
]
}{- "id": 3,
- "internal_id": "distributor-ESP",
- "is_active": true,
- "minimum_order_amount": {
- "amount": "100.00",
- "currency": "EUR"
}, - "customers_count": 74,
- "variant_prices_count": 1942,
- "global_discount": "10.00",
- "category_discounts": [
- {
- "categories": [
- {
- "id": 23,
- "internal_id": "CAT-023",
- "translations": {
}
}
], - "discount": "5.00"
}
], - "brand_discounts": [
- {
- "brands": [
- {
- "id": 1,
- "name": "Sample Brand",
- "internal_id": "BRAND-001",
}, - {
- "id": 3,
- "name": "Another Brand",
- "internal_id": "BRAND-003",
}
], - "discount": "15.00"
}
]
}Retrieve a paginated list of variant prices configured for a specific price list, with optional filtering and ordering. Use this endpoint to inspect fixed prices, minimum quantities and quantity multiples applied by the price list to specific variants.
This endpoint returns customer-specific variant prices configured in the selected price list. It does not return the standard catalog prices configured for variants.
| id required | integer |
| ean | Array of strings Filter price list variant prices by a comma-separated list of EAN/UPC codes. Max 200 EANs. |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 500 Default: 100 Number of results to return per page. |
| product_ids | Array of integers Filter price list variant prices by a comma-separated list of product IDs. Max 200 IDs. |
| product_internal_ids | Array of strings Filter price list variant prices by a comma-separated list of product internal IDs. Max 200 IDs. |
| sku | Array of strings Filter price list variant prices by a comma-separated list of SKUs. Max 200 SKUs. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| supplier_id | integer Filter price list variant prices by variant's product supplier ID. |
| supplier_internal_id | Array of strings Filter price list variant prices by variant's product supplier internal ID. |
| variant_ids | Array of integers Filter price list variant prices by a comma-separated list of variant IDs. Max 200 IDs. |
| variant_internal_ids | Array of strings Filter price list variant prices by a comma-separated list of variant internal IDs. Max 200 IDs. |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- {
- "variant_id": 201,
- "variant_internal_id": "PIM-V-987",
- "product_id": 1204,
- "product_internal_id": "PROD-001",
- "ean": "8431234567890",
- "sku": "sneaker-41",
- "supplier_id": 15,
- "supplier_internal_id": "SUP-001",
- "display_name": "Zapatilla Deportiva Talla 41",
- "price": {
- "amount": "54.75",
- "currency": "EUR"
}, - "min_quantity": 5,
- "quantity_factor": 5
}
]
]
}Deletes all variant prices configured in the price list.
This operation removes every fixed price by variant from the price list, including any variant-level minimum quantity and quantity multiple values.
This endpoint does not delete the price list itself, nor does it modify price list configuration fields such as global discounts, category discounts, brand discounts, active state or minimum order amount.
After deletion, variants affected by this price list no longer have fixed prices from this price list. They may still be affected by other price list rules, such as brand, category or global discounts.
| id required | integer |
Creates an asynchronous bulk update job to manage variant prices within a price list.
Use this endpoint to process variant prices in bulk. The operation to perform is defined by options.mode:
upsert: creates new variant prices and updates existing ones. Existing prices that are not included in the payload remain unchanged.delete: removes the provided variant prices from the price list.Variants can be matched using one of the supported identifiers defined by options.match_by: variant_id, variant_internal_id, ean or sku_supplier.
This endpoint only manages customer-specific variant prices configured within a price list. Price list configuration fields such as global discounts, category discounts, brand discounts, active state and minimum order amount are managed through the price list CRUD endpoints.
This endpoint does not process the update within the request cycle. Before creating the job, OpenTiendas performs an initial validation of the request, including JSON format, payload structure, payload size and required top-level fields.
If the request fails this initial validation, no job is created and an error response is returned. The response may be 413 Request Entity Too Large if the payload exceeds the maximum allowed size, or 400 Bad Request for other validation errors.
If the request passes this initial validation, the endpoint creates and queues a job, then returns 202 Accepted with the corresponding job_id. This confirms that the request has been accepted for asynchronous processing, but does not mean that all reference prices have already been updated successfully.
Record-level validations and update operations are performed later, during job processing.
The progress and result of the operation can be reviewed using the returned job_id.
The job log includes processing information, validation errors, affected variant identifiers when available, and a final summary with the total processed and failed records.
Maximum request payload: 10 MB. Requests exceeding this limit are rejected.
| id required | integer |
required | Array of objects (PriceListVariantPriceUpdate) Array of reference prices to process. The array cannot be empty. Each object must include the field used for matching, as defined by |
required | object Options for the bulk update operation. |
{- "prices": [
- {
- "variant_internal_id": "VAR-001",
- "price": {
- "amount": "4.75",
- "currency_code": "EUR"
}, - "minimum_quantity": 5,
- "quantity_multiple": 5
}
], - "options": {
- "match_by": "variant_internal_id",
- "mode": "upsert"
}
}[- {
- "job_id": "f7c9a6d1-3b2e-4f85-9a71-6d4c8e2b5f03",
- "status": "pending"
}
]A Product is a catalog container that groups one or more variants under a single listing (name, description, brand, categories, etc.). Products always have at least one variant. Pricing, inventory, and other operational data are managed at the variant level.
The product_structure field indicates whether the product supports multiple variants (with_variants) or is a single-variant product (simple).
Fixed fields: id
Default fields: internal_id, product_structure, status, product_kind, model_code, tax_category, images, variants_count, url, name, slug, slug_base
Nested objects: supplier, brand, categories, variants
No nested objects are included by default. Use the includes query parameter to include nested objects in the response.
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Links existing OpenTiendas products and variants with identifiers from external systems such as a PIM or ERP.
This endpoint is typically used during the initial migration or first synchronization to populate internal_id values for existing catalog records.
This endpoint does not process the link operation within the request cycle. Before creating the job, OpenTiendas performs an initial validation of the request, including JSON format, payload structure, payload size and required top-level fields.
If the request fails this initial validation, no job is created and an error response is returned. The response may be 413 Request Entity Too Large if the payload exceeds the maximum allowed size, or 400 Bad Request for other validation errors.
If the request passes this initial validation, the endpoint creates and queues a job, then returns 202 Accepted with the corresponding job_id. This confirms that the request has been accepted for asynchronous processing, but does not mean that all identifiers have already been linked successfully.
Record-level matching, validations, and link operations are performed later, during job processing.
Each item attempts to match an existing variant using ean or sku + supplier_internal_id.
When exactly one matching variant is found, the provided internal_id values are assigned to the variant and/or its parent product.
If no matching variant is found, or if the match is ambiguous, the item is not linked and the result is reported in the job log.
This endpoint only links identifiers. It does not create, update, or delete catalog data.
Once linked, the assigned internal_id values can be used for bulk catalog updates and other operations.
The progress and result of the operation can be reviewed using the returned job_id.
The job log includes processing information, validation errors, match errors, affected product or variant identifiers when available, and a final summary with the total processed and failed records.
Maximum request payload: 10 MB. Requests exceeding this limit are rejected.
required | Array of objects (LinkIDsItem) List of items to link identifiers for. For each item, the provided internal IDs will be linked to the corresponding variant and its parent product based on the available identifiers (EAN, SKU + supplier). Each item must include exactly one of the following identifier options to match the variant:
Additionally, each item must include at least one of the following internal ID fields to be linked:
| ||||||||||
Array
| |||||||||||
{- "items": [
- {
- "ean": "8431234567890",
- "product_internal_id": "PIM-P-123",
- "variant_internal_id": "PIM-V-987"
}
]
}[- {
- "job_id": "91233456-9c4b-4d2a-8f1e-abcdef123456",
- "status": "pending"
}
]Retrieve a paginated list of products with optional filtering and ordering.
| brand_ids | Array of numbers Filter products whose |
| category_ids | Array of integers Filter products by a comma-separated list of category IDs. Max 50 IDs. Descendant categories are included. For example, filtering by the Clothes category returns all products assigned to that category and any of its subcategories (e.g. Trousers and Shirts). |
| created_at_from | string <date-time> Filter products created from the given date and time. Uses |
| created_at_to | string <date-time> Filter products created up to the given date and time. Uses |
| ean | Array of strings Filter products by a comma-separated list of EAN/UPC codes. Max 200 EANs. Exact match on |
| internal_ids | Array of strings Filter products by a comma-separated list of product internal IDs. Exact match on |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| product_ids | Array of integers Filter products by a comma-separated list of product IDs. Exact match on |
| product_structure | string Enum: "simple" "with-variants" Filter products by product structure.
|
| sku | Array of strings Filter products by a comma-separated list of SKUs. Max 200 SKUs. Exact match case-insensitive on |
| slug | string Filter products by a comma-separated list of slugs. Max 200 slugs. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| status | string Enum: "published" "unpublished" Filter products by publication status.
|
| supplier_ids | Array of numbers Filter products that have at least one supplier in the comma-separated list of supplier IDs. Max 50 IDs. |
| updated_at_from | string <date-time> Filter products updated on or after the given date and time. Uses Useful for incremental synchronization and change tracking. This filter is intended to help detect products that may need to be re-synchronized, but should not be treated as a complete change history. |
| updated_at_to | string <date-time> Filter products updated on or before the given date and time. Uses Useful for incremental synchronization and change tracking. This filter is intended to help detect products that may need to be re-synchronized, but should not be treated as a complete change history. |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- {
- "id": 55,
- "internal_id": "mountain-backpack",
- "product_structure": "simple",
- "status": "unpublished",
- "product_kind": "physical",
- "model_code": "mtbpk_2026",
- "tax_category": "reduced",
- "images": [
- {
- "id": 201,
- "position": 0
}, - {
- "id": 202,
- "position": 1
}
], - "variants_count": 1,
- "translations": {
- "en-GB": {
- "name": "Mountain Backpack",
- "slug_base": "mountain-backpack",
- "slug": "mountain-backpack-b37"
}, - "es-ES": {
- "name": "Mochila de Montaña",
- "slug_base": "mochila-montana",
- "slug": "mochila-montana-b37"
}
}
}, - {
- "id": 56,
- "internal_id": "city-bike",
- "product_structure": "simple",
- "status": "published",
- "product_kind": "physical",
- "model_code": "ctybk_2026",
- "tax_category": "standard",
- "images": [
- {
- "id": 301,
- "position": 0
}
], - "variants_count": 1,
- "translations": {
- "en-GB": {
- "name": "City Bike",
- "slug_base": "city-bike",
- "slug": "city-bike-b38"
}, - "es-ES": {
- "name": "Bicicleta Urbana",
- "slug_base": "bicicleta-urbana",
- "slug": "bicicleta-urbana-b38"
}
}
}
]
]
}Retrieve detailed information about a specific product by its ID.
| id required | integer |
{- "id": 42,
- "internal_id": "urban-shoe",
- "product_structure": "with-variants",
- "status": "published",
- "product_kind": "physical",
- "model_code": "urbn_2026",
- "tax_category": "standard",
- "images": [
- {
- "id": 101,
- "position": 0
}, - {
- "id": 102,
- "position": 1
}
], - "variants_count": 3,
- "translations": {
- "en-GB": {
- "name": "Urban Shoe",
- "slug_base": "urban-shoe",
- "slug": "urban-shoe-2026"
}, - "es-ES": {
- "name": "Zapato Urbano",
- "slug_base": "zapato-urbano",
- "slug": "zapato-urbano-2026"
}
}
}Creates an asynchronous bulk upsert job to create or updateproducts and their related data from the provided payload.
This endpoint does not process the update within the request cycle. Before creating the job, OpenTiendas performs an initial validation of the request, including JSON format, payload structure, payload size and required top-level fields.
If the request fails this initial validation, no job is created and an error response is returned. The response may be 413 Request Entity Too Large if the payload exceeds the maximum allowed size, or 400 Bad Request for other validation errors.
If the request passes this initial validation, the endpoint creates and queues a job, then returns 202 Accepted with the corresponding job_id. This confirms that the request has been accepted for asynchronous processing, but does not mean that all variants have already been updated successfully.
Record-level validations and update operations are performed later, during job processing.
The progress and result of the operation can be reviewed using the returned job_id.
The job log includes processing information, validation errors, affected variant identifiers when available, and a final summary with the total processed and failed records.
When updating existing variants, it is not necessary to send the full variant data. The request only needs to include the identifier required by match_by and the fields that should be modified.
Supported match_by values are id and internal_id. id matches records using the OpenTiendas platform identifier. internal_id matches records using the custom internal identifier provided in the payload.
Maximum request payload: 10 MB. Requests exceeding this limit are rejected.
required | Array of objects (ProductWrite) List of products to create or update. Each product must include the field used for matching, as defined by
|
required | object Options for bulk upsert operation. Must include the 'match_by' field to specify how products should be matched for updates. |
{- "products": [
- {
- "internal_id": "mountain-backpack",
- "product_structure": "simple",
- "status": "unpublished",
- "product_kind": "physical",
- "stock_management": "default",
- "online_availability": "shipping-only",
- "model_code": "mtbpk_2026",
- "tax_category": "standard",
- "supplier_id": 7,
- "brand_id": 5,
- "category_ids": [
- 21
], - "images": [
], - "variants": [
- {
- "internal_id": "mountain-backpack-variant",
- "sku": "mtbpk-2026",
- "ean": "9876543210123",
- "status": "unpublished",
- "min_quantity": 1,
- "quantity_factor": 1,
- "warehouse_stock": 50,
- "supplier_stock": 100,
- "prices": {
- "market_en": {
- "list_price": {
- "amount": "230.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "179.99",
- "currency": "EUR"
}
}, - "market_es": {
- "list_price": {
- "amount": "230.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "149.99",
- "currency": "EUR"
}
}
}
}
], - "translations": {
- "en-GB": {
- "name": "Mountain Backpack",
- "description": "The perfect backpack for mountain adventures.",
- "body_html": "<p>The perfect backpack for <b>mountain adventures</b>. Spacious, durable, and comfortable.</p>",
- "long_name": "Mountain Backpack - Model 2026",
- "meta_title": "Buy Mountain Backpack Online",
- "meta_description": "Get the Mountain Backpack, the perfect backpack for mountain adventures. Spacious, durable, and comfortable. Available now."
}, - "es-ES": {
- "name": "Mochila de Montaña",
- "description": "La mochila perfecta para aventuras en la montaña.",
- "body_html": "<p>La mochila perfecta para <b>aventuras en la montaña</b>. Espaciosa, duradera y cómoda.</p>",
- "long_name": "Mochila de Montaña - Modelo 2026",
- "meta_title": "Compra la Mochila de Montaña Online",
- "meta_description": "Consigue la Mochila de Montaña, la mochila perfecta para aventuras en la montaña. Espaciosa, duradera y cómoda. Disponible ahora."
}
}
}, - {
- "internal_id": "city-bike",
- "product_structure": "with-variants",
- "status": "published",
- "product_kind": "physical",
- "stock_management": "deny-without-own-stock",
- "online_availability": "pickup-only",
- "model_code": "ctybk_2026",
- "tax_category": "standard",
- "supplier_id": 8,
- "brand_id": 6,
- "category_ids": [
- 22,
- 23,
- 74
], - "variants": [
- {
- "internal_id": "city-bike-m-red-2026",
- "sku": "ctybk-m-red-2026",
- "ean": "9876543210124",
- "status": "published",
- "warehouse_stock": 10,
- "prices": {
- "market_en": {
- "list_price": {
- "amount": "499.99",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "429.99",
- "currency": "EUR"
}
}, - "market_es": {
- "list_price": {
- "amount": "549.99",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "479.99",
- "currency": "EUR"
}, - "flash_offer": {
- "price": {
- "amount": "399.99",
- "currency": "EUR"
}, - "valid_from": "2026-04-01",
- "valid_until": "2026-04-07"
}
}
}, - "translations": {
- "en-GB": {
- "name": "Red / M"
}, - "es-ES": {
- "name": "Talla M / Rojo"
}
}
}, - {
- "internal_id": "city-bike-m-blue-2026",
- "sku": "ctybk-m-blue-2026",
- "ean": "9876543210125",
- "status": "published",
- "warehouse_stock": 5,
- "prices": {
- "market_en": {
- "list_price": {
- "amount": "499.99",
- "currency": "EUR"
}
}, - "market_es": {
- "list_price": {
- "amount": "549.99",
- "currency": "EUR"
}
}
}, - "translations": {
- "en-GB": {
- "name": "Blue / M"
}, - "es-ES": {
- "name": "Talla M / Azul"
}
}
}
], - "translations": {
- "en-GB": {
- "name": "City Bike",
- "description": "The ideal bike for urban commuting.",
- "body_html": "<p>The ideal bike for <b>urban commuting</b>. Stylish, comfortable, and efficient.</p>",
- "long_name": "City Bike - Model 2026",
- "meta_title": "Buy City Bike Online",
- "meta_description": "Get the City Bike, the ideal bike for urban commuting. Stylish, comfortable, and efficient. Available now."
}, - "es-ES": {
- "name": "Bicicleta Urbana",
- "description": "La bicicleta ideal para desplazarse por la ciudad.",
- "body_html": "<p>La bicicleta ideal para <b>desplazarse por la ciudad</b>. Elegante, cómoda y eficiente.</p>",
- "long_name": "Bicicleta Urbana - Modelo 2026",
- "meta_title": "Compra la Bicicleta Urbana Online",
- "meta_description": "Consigue la Bicicleta Urbana, la bicicleta ideal para desplazarse por la ciudad. Elegante, cómoda y eficiente. Disponible ahora."
}
}
}
], - "options": {
- "match_by": "internal_id"
}
}[- {
- "job_id": "123e4567-e89b-12d3-a456-426614174000",
- "status": "pending"
}
]A Review represents customer feedback about a product (optionally a specific variant) or about the store. Reviews can be published/unpublished and include rating, content, author and other information.
Fixed fields: id
Default fields: locale, status, rating, created_at, type
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of reviews with optional filtering and ordering.
| created_at_from | string <date-time> Filter reviews created from this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T00:00:00Z). If the time component is omitted, 00:00:00 is assumed. |
| created_at_to | string <date-time> Filter reviews created up to this date/time (inclusive) in ISO 8601 format (e.g. 2023-01-01T23:59:59Z). If the time component is omitted, 23:59:59 is assumed. |
| locale | string Enum: "ca-ES" "da-DK" "de-DE" "el-GR" "en-GB" "es-ES" "fr-FR" "hr-HR" "it-IT" "nl-NL" "pl-PL" "pt-PT" "ru-RU" "sv-SE" Filter by locale.
|
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
| product_id | number Filter reviews by product ID. |
| rating | Array of integers Filter reviews by a rating or a list of ratings (comma-separated). Valid rating values are 1 to 5. |
| sort | string Which field to use when ordering the results. Use '_asc' or '_desc' suffix to specify ascending or descending order. Valid values are: Default value: |
| status | string Enum: "published" "unpublished" Filter reviews by publication status.
|
| type | string or null Enum: null "product" "store" Filter reviews by type. |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- {
- "id": 2,
- "locale": "en-GB",
- "status": "published",
- "rating": 5,
- "created_at": "2019-08-24T14:15:22Z",
- "type": "product"
}
]
}Create a new review with the provided details.
| locale required | string Enum: "es-ES" "ca-ES" "en-GB" "fr-FR" "it-IT" "pt-PT" "de-DE" "ru-RU" "nl-NL" "sv-SE" "da-DK" "pl-PL" "el-GR" "hr-HR" Locale code in ISO format (e.g., es-ES, en-GB).Format follows ISO 639-1 (language) and ISO 3166-1 alpha-2 (country) standards.
|
| status | string Enum: "published" "unpublished" Status of the object: 'published' or 'unpublished'.
|
| rating | integer [ 1 .. 5 ] Rating from 1 (minimum) to 5 (maximum). |
| content required | string Content of the review. |
| created_at | string <date-time> Date and time in ISO 8601 format (e.g., 2023-10-01T12:00:00Z). Microseconds are not included. |
| reviewer_name | string Name of the reviewer. |
| reviewer_email required | string <email> Email of the reviewer. |
| order_id | integer or null (Order number) ID of the order associated with the review, if applicable. If a review is associated with an order, it will be considered a verified review. This verification helps build trust and transparency for shoppers browsing your store. |
| customer_id | integer or null ID of the customer (contact) who wrote the review. |
| type required | string Enum: "product" "store" Type of review: 'product' for product reviews, 'store' for store reviews.
|
| product_id | integer or null ID of the product being reviewed. Only for 'product' reviews. |
| variant_id | integer or null ID of the variant being reviewed. Only for 'product' reviews. |
{- "locale": "en-GB",
- "status": "published",
- "rating": 5,
- "content": "The product matches the description perfectly. Highly recommended.",
- "created_at": "2024-01-15T09:22:10Z",
- "reviewer_name": "Emily Smith",
- "reviewer_email": "emily.smith@example.com",
- "order_id": 123456,
- "customer_id": 789,
- "type": "product",
- "product_id": 2532,
- "variant_id": null
}[- {
- "id": 3,
- "locale": "en-GB",
- "status": "published",
- "rating": 5,
- "created_at": "2024-01-15T09:22:10Z",
- "type": "product"
}
]Retrieve detailed information about a specific review by its ID.
| id required | integer |
{- "id": 3,
- "locale": "en-GB",
- "status": "published",
- "rating": 5,
- "created_at": "2024-01-15T09:22:10Z",
- "type": "store"
}Update an existing review's details.
| id required | integer |
| locale | string Enum: "es-ES" "ca-ES" "en-GB" "fr-FR" "it-IT" "pt-PT" "de-DE" "ru-RU" "nl-NL" "sv-SE" "da-DK" "pl-PL" "el-GR" "hr-HR" Locale code in ISO format (e.g., es-ES, en-GB).Format follows ISO 639-1 (language) and ISO 3166-1 alpha-2 (country) standards.
|
| status | string Enum: "published" "unpublished" Status of the object: 'published' or 'unpublished'.
|
| rating | integer [ 1 .. 5 ] Rating from 1 (minimum) to 5 (maximum). |
| content | string Content of the review. |
| created_at | string <date-time> Date and time in ISO 8601 format (e.g., 2023-10-01T12:00:00Z). Microseconds are not included. |
| reviewer_name | string Name of the reviewer. |
| reviewer_email | string <email> Email of the reviewer. |
| order_id | integer or null (Order number) ID of the order associated with the review, if applicable. If a review is associated with an order, it will be considered a verified review. This verification helps build trust and transparency for shoppers browsing your store. |
| customer_id | integer or null ID of the customer (contact) who wrote the review. |
| type | string Enum: "product" "store" Type of review: 'product' for product reviews, 'store' for store reviews.
|
| product_id | integer or null ID of the product being reviewed. Only for 'product' reviews. |
| variant_id | integer or null ID of the variant being reviewed. Only for 'product' reviews. |
{- "content": "The shopping experience was good.",
- "rating": 4
}{- "id": 3,
- "locale": "en-GB",
- "status": "published",
- "rating": 4,
- "created_at": "2024-01-15T09:22:10Z",
- "type": "store"
}The Store resource represents the global configuration and public identity of the shop. It exposes high-level information such as the store name or domains.
Retrieves the store's return policy, and the name, domain, logo URL, and configured email accounts for each supported locale.
{- "return_policy": {
- "applicable_countries": [
- "ES",
- "DE",
- "FR"
], - "return_policy_country": "ES",
- "return_days": 30,
- "return_method": "by_mail",
- "return_fees": "customer_pays",
- "refund_type": "full",
- "return_label_source": "download_and_print",
- "item_condition": "new"
}, - "translations": {
- "en-GB": {
- "name": "My OpenTiendas Store",
- "domain": "example.com",
- "orders_email_account": "orders@example.com",
- "contact_email_account": "contact@example.com",
- "promotions_email_account": "promotions@example.com"
}, - "fr-FR": {
- "name": "Ma boutique OpenTiendas",
- "domain": "example.fr",
- "orders_email_account": "orders@example.fr",
- "contact_email_account": "contact@example.fr",
- "promotions_email_account": "promotions@example.fr"
}, - "es-ES": {
- "name": "Mi tienda OpenTiendas",
- "domain": "example.es",
- "orders_email_account": "orders@example.es",
- "contact_email_account": "contact@example.es",
- "promotions_email_account": "promotions@example.es"
}
}
}A Supplier represents a company or entity that provides products to the store. Suppliers are used internally for stock sourcing, logistics, purchasing workflows, and reporting. Supplier data is not localized and is intended for back-office and integration use.
Fixed fields: name
Default fields: id
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Retrieve a paginated list of suppliers.
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- {
- "id": 1,
- "name": "Example Supplier"
}
]
]
}Create a new supplier with the provided details.
| name required | string Name of the supplier. |
| internal_id required | string Internal ID for the supplier. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| description | string Internal description of the supplier. |
{- "name": "New Supplier",
- "internal_id": "SUP-002",
- "description": "A newly created supplier"
}{- "id": 2,
- "name": "New Supplier"
}Update an existing supplier's details.
| id required | integer |
| name | string Name of the supplier. |
| internal_id | string Internal ID for the supplier. This alternative identifier is intended for linking it with external systems and managing it through imports or API integrations. |
| description | string Internal description of the supplier. |
{- "description": "Updated description for Supplier A."
}{- "id": 1,
- "name": "Supplier A"
}A Variant represents a purchasable SKU of a product (the exact item a customer buys, e.g. "T-shirt / Black / M"). Every variant belongs to a parent product. Pricing, inventory, and other operational data are managed at the variant level.
Fixed fields: id
Default fields: internal_id, sku, ean, status, available_stock, name, selling_price
See the Field selection and response shape page for the global rules governing field selection and related resource inclusion.
Links existing OpenTiendas products and variants with identifiers from external systems such as a PIM or ERP.
This endpoint is typically used during the initial migration or first synchronization to populate internal_id values for existing catalog records.
This endpoint does not process the link operation within the request cycle. Before creating the job, OpenTiendas performs an initial validation of the request, including JSON format, payload structure, payload size and required top-level fields.
If the request fails this initial validation, no job is created and an error response is returned. The response may be 413 Request Entity Too Large if the payload exceeds the maximum allowed size, or 400 Bad Request for other validation errors.
If the request passes this initial validation, the endpoint creates and queues a job, then returns 202 Accepted with the corresponding job_id. This confirms that the request has been accepted for asynchronous processing, but does not mean that all identifiers have already been linked successfully.
Record-level matching, validations, and link operations are performed later, during job processing.
Each item attempts to match an existing variant using ean or sku + supplier_internal_id.
When exactly one matching variant is found, the provided internal_id values are assigned to the variant and/or its parent product.
If no matching variant is found, or if the match is ambiguous, the item is not linked and the result is reported in the job log.
This endpoint only links identifiers. It does not create, update, or delete catalog data.
Once linked, the assigned internal_id values can be used for bulk catalog updates and other operations.
The progress and result of the operation can be reviewed using the returned job_id.
The job log includes processing information, validation errors, match errors, affected product or variant identifiers when available, and a final summary with the total processed and failed records.
Maximum request payload: 10 MB. Requests exceeding this limit are rejected.
required | Array of objects (LinkIDsItem) List of items to link identifiers for. For each item, the provided internal IDs will be linked to the corresponding variant and its parent product based on the available identifiers (EAN, SKU + supplier). Each item must include exactly one of the following identifier options to match the variant:
Additionally, each item must include at least one of the following internal ID fields to be linked:
| ||||||||||
Array
| |||||||||||
{- "items": [
- {
- "ean": "8431234567890",
- "product_internal_id": "PIM-P-123",
- "variant_internal_id": "PIM-V-987"
}
]
}[- {
- "job_id": "91233456-9c4b-4d2a-8f1e-abcdef123456",
- "status": "pending"
}
]Retrieve a paginated list of variants of a product.
| product_id required | integer |
| page | integer A page number within the paginated result set. |
| per_page | integer <= 100 Default: 50 Number of results to return per page. |
{- "pagination": {
- "current_page": 3,
- "per_page": 50,
- "total": 223,
- "total_pages": 5,
}, - "data": [
- [
- {
- "id": 201,
- "internal_id": "PIM-V-987",
- "sku": "sneaker-41",
- "ean": "8431234567890",
- "status": "published",
- "available_stock": 270,
- "prices": {
- "market_es": {
- "selling_price": {
- "amount": "89.99",
- "currency": "EUR"
}, - "list_price": {
- "amount": "109.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "89.99",
- "currency": "EUR"
}, - "flash_offer": null
}
}, - "translations": {
- "es-ES": {
- "name": "Zapatilla Deportiva Talla 41"
}, - "en-GB": {
- "name": "Sports Sneaker Size 41"
}
}
}, - {
- "id": 201,
- "internal_id": "PIM-V-988",
- "sku": "sneaker-42",
- "ean": "8431234567890",
- "status": "published",
- "available_stock": 265,
- "prices": {
- "market_es": {
- "selling_price": {
- "amount": "89.99",
- "currency": "EUR"
}, - "list_price": {
- "amount": "109.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "89.99",
- "currency": "EUR"
}, - "flash_offer": null
}
}, - "translations": {
- "es-ES": {
- "name": "Zapatilla Deportiva Talla 42"
}, - "en-GB": {
- "name": "Sports Sneaker Size 42"
}
}
}
]
]
}Creates an asynchronous bulk update job to update variants and their related data from the provided payload.
This endpoint does not process the update within the request cycle. Before creating the job, OpenTiendas performs an initial validation of the request, including JSON format, payload structure, payload size and required top-level fields.
If the request fails this initial validation, no job is created and an error response is returned. The response may be 413 Request Entity Too Large if the payload exceeds the maximum allowed size, or 400 Bad Request for other validation errors.
If the request passes this initial validation, the endpoint creates and queues a job, then returns 202 Accepted with the corresponding job_id. This confirms that the request has been accepted for asynchronous processing, but does not mean that all variants have already been updated successfully.
Record-level validations and update operations are performed later, during job processing.
The progress and result of the operation can be reviewed using the returned job_id.
The job log includes processing information, validation errors, affected variant identifiers when available, and a final summary with the total processed and failed records.
After the job is completed/finished, changes may take a short time to propagate across all parts of the shop.
When updating existing variants, it is not necessary to send the full variant data. The request only needs to include the identifier required by match_by and the fields that should be modified.
Supported match_by values are id, internal_id, ean, and sku_supplier. When using sku_supplier, the request must include both the SKU and the supplier internal ID.
Fields marked as required in this schema apply to variant creation.
Maximum request payload: 10 MB. Requests exceeding this limit are rejected.
required | Array of objects (Variant) List of variants to update. Each variant must include the field used for matching, as defined by
|
required | object Options for bulk update operation. Must include the 'match_by' field to specify how variants should be matched for updates. |
{- "variants": [
- {
- "id": 201,
- "internal_id": "PIM-V-987",
- "sku": "urbn-41",
- "ean": "1234567890123",
- "status": "published",
- "min_quantity": 1,
- "quantity_factor": 1,
- "supplier_stock": 250,
- "warehouse_stock": 20,
- "cost_price": {
- "amount": "50.00",
- "currency": "EUR"
}, - "prices": {
- "market_en": {
- "list_price": {
- "amount": "95.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "89.99",
- "currency": "EUR"
}
}, - "market_es": {
- "list_price": {
- "amount": "109.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "99.99",
- "currency": "EUR"
}, - "flash_offer": {
- "price": {
- "amount": "94.99",
- "currency": "EUR"
}, - "valid_from": "2025-06-25",
- "valid_until": "2025-06-30"
}
}
}, - "translations": {
- "en-GB": {
- "name": "41"
}, - "es-ES": {
- "name": "41"
}
}
}, - {
- "id": 202,
- "internal_id": "PIM-V-988",
- "sku": "urbn-42",
- "ean": "1234567890124",
- "status": "published",
- "min_quantity": 1,
- "quantity_factor": 1,
- "supplier_stock": 300,
- "warehouse_stock": 50,
- "cost_price": {
- "amount": "55.00",
- "currency": "EUR"
}, - "prices": {
- "market_en": {
- "list_price": {
- "amount": "100.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "94.99",
- "currency": "EUR"
}
}, - "market_es": {
- "list_price": {
- "amount": "115.00",
- "currency": "EUR"
}, - "offer_price": {
- "amount": "104.99",
- "currency": "EUR"
}
}
}, - "translations": {
- "en-GB": {
- "name": "42"
}, - "es-ES": {
- "name": "42"
}
}
}
], - "options": {
- "match_by": "id"
}
}[- {
- "job_id": "6582ffe3-9c4b-4d2a-8f1e-123456789abc",
- "status": "pending"
}
]