> For the complete documentation index, see [llms.txt](https://docs.akinon.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akinon.com/tutorials/marketplace-dashboard/trendyol/product-update.md).

# Product Update

This tutorial explains how the **Product Update** process works for the **Trendyol** integration in the Marketplace Dashboard: which products are picked up, which requests are made to Omnitron and Trendyol (with example data), how the end-to-end process works, and how to read the error codes it produces.

{% hint style="info" %}
For channel-level setup (feature flags, category mapping, failed integration rules, etc.), see [Trendyol Marketplace Setup Configurations](/technical-guides/marketplace-dashboard/trendyol-marketplace-setup-configurations.md) tutorial.
{% endhint %}

{% hint style="info" %}
This tutorial covers products that are **already listed and approved on Trendyol**. For products that have never been sent, or that are still waiting for Trendyol's approval, see [Product Insert](/tutorials/marketplace-dashboard/trendyol/product-insert.md).
{% endhint %}

## <mark style="color:red;">What is Product Update?</mark>

**Product Update** keeps the **content** of products that are **already successfully listed on Trendyol** in sync with Omnitron — description, images, and attributes. On the **Logs** screen, this process appears under the flow name **Product Update**.

{% hint style="warning" %}
**This flow only handles content.** Price and stock changes are **not** sent by this flow — they are synchronized by two separate, independently scheduled flows that appear on the Logs screen as **Price** and **Stock**. This tutorial does not cover them in detail; see the **`send_updated_product_price`** / **`send_updated_product_stock`** feature flags in the [Trendyol Marketplace Setup Configurations](/technical-guides/marketplace-dashboard/trendyol-marketplace-setup-configurations.md) tutorial for their schedule and settings.
{% endhint %}

## <mark style="color:red;">When Does It Run?</mark>

* Controlled by the **`send_products_updated`** feature flag in the channel settings. When active, it runs automatically **every 5 minutes**.
* It can also be triggered manually from the **Dashboard** screen — a dedicated **Product Update** option exists in the trigger area, separate from the **Product Create** (insert) trigger. Alternatively, use **"Update Bulk Product Version Date"** under **Update by Uploading a File** in the channel settings to force a specific product to be picked up.
* Runs are not overlapped: if a previous run of this flow is still in progress when the next 5-minute mark is reached, the new run waits for the running one to finish before it starts.

## <mark style="color:red;">Which Products Are Eligible?</mark>

A product is picked up for update only if it:

* Is already **listed on Trendyol** (see [Approval Is Required for a Real Success](/tutorials/marketplace-dashboard/trendyol/product-insert.md#approval-is-required-for-a-real-success) in Product Insert).
* Has **content** (description, images, or attributes) that has changed in Omnitron since the last successful sync.

During enrichment the flow also requires the product to already have **mapped attributes**, a **category**, and a **price record** in Omnitron (its value isn't sent by this flow, only its presence is checked) — missing any of these stops the product with the matching error code (see below).

## <mark style="color:red;">Fetching Changed Products from Omnitron</mark>

Products with pending content changes are fetched from Omnitron:

```
GET {omnitron_url}/api/v1/channel/{channel_id}/products/updates/
    ?product_type=0
    &sort=modified_date
    &limit=50&page=1
```

For each product returned, Omnitron is queried again to collect its current **mapped attributes**, **attribute configs**, **category**, and (for validation only) **price** — the same enrichment step used by Product Insert, minus stock.

## <mark style="color:red;">Resolving Trendyol's Content ID</mark>

Unlike Product Insert, an update needs to tell Trendyol **which existing listing** to update. The flow first checks whether Trendyol's `contentId` is already kept on the product:

* **If it is**, that value is reused directly.
* **If it isn't**, Trendyol is queried for the product by barcode, and the returned `contentId` is stored on the product so future updates skip this lookup:

```
GET {mp_host}/product/sellers/{supplierId}/product/{barcode}/
```

If Trendyol doesn't return a `contentId` for the barcode (e.g. the product was removed from the Trendyol panel), the product stops here with error code `2004`.

## <mark style="color:red;">Sending the Update to Trendyol</mark>

Once enriched, the product is converted into Trendyol's product schema and sent as a single request:

```
PUT {mp_host}/product/sellers/{supplierId}/products
```

```json
{
  "items": [
    {
      "contentId": 123456789,
      "barcode": "TY-100234",
      "stockCode": "TY-100234",
      "productMainId": "TY-100234",
      "categoryId": 411,
      "title": "Example Product Title",
      "description": "Example product description...",
      "brandId": 1791,
      "dimensionalWeight": 1,
      "currencyType": "TRY",
      "vatRate": 10,
      "images": [{ "url": "https://.../image1.jpg" }],
      "attributes": [
        { "attributeId": 338, "attributeValueId": 4290 },
        ...
      ]
    }
  ]
}
```

### Where Each Field Comes From

| Payload field       | Source                                                               | If not mapped / not available                                                                         |
| ------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `contentId`         | Trendyol's existing content ID for this listing                      | — (see [Resolving Trendyol's Content ID](#resolving-trendyols-content-id) above; required)            |
| `title`             | Mapped attribute **`Title`**                                         | `product.name`                                                                                        |
| `stockCode`         | Mapped attribute **`StockCode`**                                     | `product.sku`                                                                                         |
| `productMainId`     | Mapped attribute **`RemoteBaseCode`**                                | The product's **parent** product's ID (if it's a variant); if there's no parent, the product's own ID |
| `description`       | Mapped attribute **`Description`**                                   | Empty string `""`                                                                                     |
| `dimensionalWeight` | Mapped attribute **`DimensionWeight`**, then **`DimensionalWeight`** | `1`                                                                                                   |
| `currencyType`      | Mapped attribute **`CurrencyType`**                                  | `"TRY"`                                                                                               |
| `vatRate`           | Omnitron's **tax rate**, truncated to a whole number                 | — (required; the product stops earlier with `2004` if there's no price record at all)                 |
| `images`            | The product's images in Omnitron                                     | Only the **first 8** are sent — any beyond that are not included                                      |
| `origin`            | Mapped attribute **`Menşei`**                                        | Empty string `""`                                                                                     |

{% hint style="warning" %}

* `title` is capped at **100 characters**, exactly like Product Insert — trimmed down to the last full word that still fits, never cutting a word in half.
* `vatRate` is **truncated, not rounded** (e.g. `8.5` becomes `8`), and Trendyol only accepts **`10`** or **`20`** — any other value causes Trendyol to **reject the entire batch outright**, not just the affected product.
* `dimensionalWeight` is read from **two possible mapped attribute names** (`DimensionWeight` is checked first, then `DimensionalWeight`) — if the product has both mapped, only the first one is used.
* Unlike the fields above, `cargoCompanyId`, `returningAddressId`, and `shipmentAddressId` are **only added to the payload if they have a value** — there's no `?:` fallback; the field is left out entirely rather than sent as empty.
  {% endhint %}

{% hint style="info" %}
`brandId` is also part of the payload but isn't a simple mapped-attribute-or-fallback lookup (it goes through separate brand resolution) — not detailed in this table.
{% endhint %}

Trendyol matches the item to the existing listing by `contentId`, updates its content, and processes the request **asynchronously**, returning a batch ID exactly like Product Insert:

```json
{ "batchRequestId": "d290f1ee-6c54-4b01-90e6-d701748f0851" }
```

{% hint style="info" %}
Notice **`quantity`**, **`listPrice`**, and **`salePrice`** are absent from this payload — Product Update never sends them. They are handled entirely by the separate **Price** and **Stock** flows mentioned above.
{% endhint %}

{% hint style="warning" %}
For a product that is **already approved on Trendyol**, Trendyol does not allow updating **`barcode`**, **`productMainId`**, **`brandId`**, **`categoryId`**, or the value of any attribute that is a **slicer** or **variant** attribute — Trendyol silently ignores changes to these fields on an approved product instead of applying them. See Trendyol's [Update Product (Approved Product) v2](https://developers.trendyol.com/docs/%C3%BCr%C3%BCn-g%C3%BCncelleme-onayl%C4%B1-%C3%BCr%C3%BCn-v2) documentation for details.
{% endhint %}

## <mark style="color:red;">Delivery Duration Sync</mark>

{% hint style="info" %}
Delivery duration is **not** part of the content-update request above — no `deliveryOption` field is sent there. It is synced by a separate step that runs right after the main content update completes for that batch.
{% endhint %}

For every product this flow processes, its **`ShippingLatency`** mapped attribute (the same one used at creation time — see [Delivery Duration and Other Optional Fields](/tutorials/marketplace-dashboard/trendyol/product-insert.md#delivery-duration-and-other-optional-fields) in the Product Insert tutorial) is re-read from Omnitron and sent to Trendyol through a dedicated endpoint:

```
POST {mp_host}/product/sellers/{supplierId}/products/delivery-info-bulk-update
```

* This runs as its own independent asynchronous batch — its own `batchRequestId`, polled separately (about every 40 seconds) — apart from the main content-update batch above.
* It only fires for products this flow has already picked up under [Which Products Are Eligible?](#which-products-are-eligible) — it is not an independently scheduled sync on its own. If a product's content hasn't changed, changing only its `ShippingLatency` mapped attribute may not be enough on its own to bring the product into this flow.
* If a product has no `ShippingLatency` value mapped, it is simply skipped for this step — other products in the same batch are still processed.

{% hint style="info" %}
Correction: unlike an earlier version of this page, `cargoCompanyId`, `returningAddressId`, and `shipmentAddressId` **are** resynced by Product Update — they're included directly in the main content-update payload above (see [Where Each Field Comes From](#where-each-field-comes-from)) whenever the matching mapped attribute has a value. Delivery duration is the only one of these four "shipping" fields that goes through this separate sync step instead of the main payload.
{% endhint %}

## <mark style="color:red;">Checking the Result</mark>

The batch result is checked periodically (about every 40 seconds) until Trendyol marks it as completed:

```
GET {mp_host}/product/sellers/{supplierId}/products/batch-requests/{batchRequestId}
```

```json
{
  "batchRequestId": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "status": "COMPLETED",
  "items": [
    {
      "requestItem": { "barcode": "TY-100234", ... },
      "status": "SUCCESS",
      "failureReasons": []
    }
  ]
}
```

{% hint style="warning" %}
This polling doesn't continue forever. The batch is only checked for as long as the channel's **"sent to remote"** window allows — by default **1 hour** from the moment it was sent, or a different duration if configured in the channel's **Failed Integration** settings (`sent_to_remote.EXPIRATION_HOUR`). If Trendyol hasn't reported the batch as `COMPLETED` by the time this window runs out, the batch is marked as **expired** and treated as a failure — the products in it are not retried automatically as "still polling," they fall back to the normal failed-product retry behavior instead.
{% endhint %}

## <mark style="color:red;">How the Process Works — Summary</mark>

1. Products with content changes are fetched from Omnitron.
2. Each product is enriched with its mapped attributes, attribute configs, category, and (for validation only) price.
3. Trendyol's `contentId` for the product is resolved — reused from Omnitron if already known, otherwise fetched from Trendyol and stored.
4. Required fields are validated; a product with missing data stops here with the relevant error code (see below).
5. Valid products are converted into Trendyol's content schema and sent as a single `PUT` batch request.
6. The batch result is polled until Trendyol reports it as completed.
7. In parallel, each product's delivery duration is re-synced to Trendyol through a separate batch request — see [Delivery Duration Sync](#delivery-duration-sync).
8. The outcome of every product is written back and becomes visible on the **Logs** screen.

## <mark style="color:red;">Monitoring</mark>

1. From the left menu, go to **Trendyol > Marketplace Operations > Logs**.
2. Filter by flow name **Product Update**.
3. Use the **SKU** or **Execution ID** filters to locate a specific product.

{% hint style="info" %}
As with Product Insert, if a log doesn't show a clear error, click the **ResponseData** box on that log row to see Trendyol's raw response, which contains the real reason for the failure.
{% endhint %}

## <mark style="color:red;">Error Codes and Explanations</mark>

| Code   | Meaning                                                                                                                                                                                                            |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `2001` | Mapping information did not come from Omnitron — the product has not been mapped through the [Mapper](/tutorials/omnitron/sales-channels/sales-channel-settings/how-to-manage-marketplace-mapping-in-omnitron.md). |
| `2002` | Attribute configuration information did not come from Omnitron.                                                                                                                                                    |
| `2004` | Either price information did not come from Omnitron, **or** Trendyol did not return a `contentId` for the product's barcode (the two cases share this code).                                                       |
| `2005` | Category information did not come from Omnitron.                                                                                                                                                                   |
| `2006` | A required attribute or brand value cannot be empty.                                                                                                                                                               |
| `2007` | An error occurred while posting the product to Trendyol.                                                                                                                                                           |
| `2008` | The product was sent to Trendyol but came back with a failed result.                                                                                                                                               |
| `2009` | The product did not come back with a result from Trendyol.                                                                                                                                                         |
| `2015` | An unexpected error occurred while preparing the data to be sent to Trendyol.                                                                                                                                      |
| `2016` | An unexpected error occurred while checking the data returned from Trendyol.                                                                                                                                       |

{% hint style="info" %}
Products that keep failing are retried according to the channel's **Failed Integration** settings. If a product stops being retried, it needs to be resent manually via the **Update by Uploading Files** option in the channel settings.
{% endhint %}

## <mark style="color:red;">Related Settings</mark>

* **Category Ids** and **Mapper** — determine which categories and attributes products can be mapped to.
* **`send_products_updated`** feature flag — enables/disables the automatic 5-minute run of this process.
* **Failed Integration** settings (`product` key) — control how long and how often failed products are retried.
* Price and stock have their own separate feature flags and Failed Integration keys (**`send_updated_product_price`** / **`productprice`**, **`send_updated_product_stock`** / **`productstock`**) — not covered by this tutorial.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.akinon.com/tutorials/marketplace-dashboard/trendyol/product-update.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
