Мерксалис

Мерксалис — API интеграций v1

Мерксалис — облачная платформа для управления товарными и складскими процессами в электронной торговле.

API интеграций предназначен для обмена данными между Мерксалис и внешними учётными, складскими и аналитическими системами. Внешняя система может передавать каталог, коды и штрихкоды товаров, а также получать нормализованные операционные данные Мерксалис.

Базовый адрес https://merxalis.ru/integration/v1 Протокол HTTPS Формат JSON, UTF-8 Версия v1 OpenAPI /integration/openapi.json

Быстрый старт

  1. Создайте API-ключ в разделе Настройки → API-ключи. Открытое значение ключа показывается один раз.
  2. Передавайте ключ в заголовке Authorization: Bearer mrx_v1_....
  3. Проверьте контекст запросом GET /context. Организация, права ключа и действующие лимиты определяются сервером по API-ключу.
  4. Для передачи каталога используйте POST /catalog/products/upsert.
  5. Для получения операционных данных используйте GET /operations.

API-ключи

API-ключ является только средством авторизации и проверки прав доступа. Каталог и операционные данные принадлежат организации, а не конкретному API-ключу.

Организация может создавать необходимое ей количество API-ключей и использовать их в своих системах по собственным правилам. Максимальный срок действия ключа — 365 дней.

Для записи каталога требуется право catalog:write, для чтения каталога — catalog:read, для чтения операционных данных — operations:read.

Каталог товаров

Каталог Мерксалис хранит канонический товар организации. Все идентификаторы передаются строками, поэтому ведущие нули сохраняются.

Минимальный пакет:

{
  "items": [
    {
      "client_ref": "row-00125",
      "internal_code": "00125",
      "name": "Фартук кухонный",
      "barcodes": [
        "4673752160115",
        "4601234567890"
      ]
    }
  ]
}

Дополнительные идентификаторы

Для внешнего стабильного идентификатора используйте массив identifiers. Его элементы содержат type, необязательный namespace, value и признак resolvable.

{
  "type": "external_id",
  "namespace": "1c",
  "value": "6fd31a5e-1fb8-11ef-9f6a-0242ac120002",
  "resolvable": false
}

internal_code и штрихкоды используются как складские идентификаторы товара. Для дополнительного идентификатора resolvable=false является значением по умолчанию.

Одно распознаваемое нормализованное значение внутри организации может вести только к одному каноническому товару. Неоднозначность между разными товарами возвращается как 409 RESOLUTION_CONFLICT.

Массовая запись

POST /catalog/products/upsert принимает до 1000 строк. Результат каждой строки возвращается отдельно. client_ref предназначен только для сопоставления строки запроса с результатом и не является идентификатором товара.

Обычный массовый upsert имеет merge-семантику: отсутствие ранее записанного штрихкода, дополнительного идентификатора или связи с маркетплейсом в новом пакете само по себе не удаляет существующее значение.

Связи с маркетплейсами

Для кабинета используется стабильный account_id, полученный через GET /marketplace-accounts. Идентификаторы товара на площадке передаются массивом external_identifiers.

Например, адаптер Wildberries использует типы nm_id и chrt_id. Общая модель не привязана к Wildberries и допускает другие наборы идентификаторов для Ozon, Яндекс Маркета и будущих площадок.

Методы каталога изменяют данные каталога Мерксалис и сами по себе не выполняют запись в API маркетплейса.

Полная синхронизация каталога

Полная синхронизация является полным снимком каталога организации. Она не принадлежит конкретному API-ключу.

  1. Откройте синхронизацию через POST /catalog/sync-runs и передайте точное expected_items.
  2. Передайте пакеты в POST /catalog/products/upsert с полученным sync_id.
  3. После успешной передачи всего снимка вызовите POST /catalog/sync-runs/{sync_id}/complete с confirm_full_snapshot=true.
{
  "mode": "full",
  "expected_items": 50000
}
{
  "confirm_full_snapshot": true
}

expected_items — количество уникальных канонических товаров полного снимка. Повторная строка того же канонического товара не увеличивает received_unique_items.

Если фактически полученное количество уникальных товаров не совпадает с expected_items, завершение возвращает 409 FULL_SYNC_INCOMPLETE, а отсутствие товаров не применяется.

Одновременно в одной организации может выполняться только одна полная синхронизация. Любой API-ключ этой же организации с правом catalog:write может продолжить работу с тем же sync_id.

Если товар отсутствует в подтверждённом полном снимке, он может быть архивирован. Товар, который был создан или существенно изменён после начала снимка, защищён от ошибочного архивирования устаревшим снимком.

Если ранее автоматически архивированный полным снимком товар появляется снова, он восстанавливается с тем же product_id.

Чтение изменений каталога

Для гарантированной инкрементальной синхронизации каталога используйте GET /catalog/changes.

Пока page.next_cursor не пуст, передавайте его в следующий запрос. После последней страницы сохраните sync_cursor для следующего цикла.

Курсоры непрозрачны: их нельзя разбирать, изменять или формировать самостоятельно.

Операционные данные Мерксалис

GET /operations предназначен для передачи внешним системам нормализованных операционных данных электронной торговли и склада, сформированных из бизнес-модели Мерксалис.

Этот метод не является прокси к API маркетплейса и не зависит от структуры Excel-выгрузки.

Важно: cursor метода /operations предназначен только для последовательной пагинации результата. Он не является курсором изменений и не гарантирует выдачу только записей, изменившихся после предыдущего обращения.

Параллельные изменения и безопасные повторы

ETag / If-Match

Товар имеет числовую version. Одиночные изменяющие операции используют ETag и требуют If-Match с ранее прочитанной версией.

If-Match: "17"

Если ресурс уже изменён, сервер возвращает 412 VERSION_MISMATCH. Если обязательный заголовок отсутствует — 428 PRECONDITION_REQUIRED.

Idempotency-Key

Изменяющие POST поддерживают Idempotency-Key. Повтор того же запроса с тем же ключом возвращает прежний логический результат. Использование того же ключа для другого запроса возвращает 409 IDEMPOTENCY_KEY_REUSED.

Повтор запроса после временной ошибки

HTTP Действие
408, 429, 500, 502, 503, 504 Запрос можно повторить с увеличивающейся задержкой. Для операции записи сохраняйте тот же Idempotency-Key. Если сервер вернул Retry-After, он имеет приоритет.
400, 401, 403, 404, 409, 412, 422, 428 Сначала исправьте запрос, права или состояние ресурса. Автоматический повтор без изменения причины не требуется.

Примеры подключения

Товар = Новый Структура;
Товар.Вставить("client_ref", "00125");
Товар.Вставить("internal_code", "00125");
Товар.Вставить("name", "Фартук кухонный");

Штрихкоды = Новый Массив;
Штрихкоды.Добавить("4673752160115");
Штрихкоды.Добавить("4601234567890");
Товар.Вставить("barcodes", Штрихкоды);

Идентификатор = Новый Структура;
Идентификатор.Вставить("type", "external_id");
Идентификатор.Вставить("namespace", "1c");
Идентификатор.Вставить(
    "value",
    "6fd31a5e-1fb8-11ef-9f6a-0242ac120002"
);

Идентификаторы = Новый Массив;
Идентификаторы.Добавить(Идентификатор);
Товар.Вставить("identifiers", Идентификаторы);

Товары = Новый Массив;
Товары.Добавить(Товар);

Тело = Новый Структура;
Тело.Вставить("items", Товары);

// POST https://merxalis.ru/integration/v1/catalog/products/upsert
// Authorization: Bearer mrx_v1_...
// Content-Type: application/json
// Idempotency-Key: Новый УникальныйИдентификатор()

Python

import uuid
import requests

token = "mrx_v1_..."

payload = {
    "items": [
        {
            "client_ref": "00125",
            "internal_code": "00125",
            "name": "Фартук кухонный",
            "barcodes": [
                "4673752160115",
                "4601234567890",
            ],
            "identifiers": [
                {
                    "type": "external_id",
                    "namespace": "erp",
                    "value": "erp-product-00125",
                    "resolvable": False,
                }
            ],
        }
    ]
}

response = requests.post(
    "https://merxalis.ru/integration/v1/catalog/products/upsert",
    headers={
        "Authorization": f"Bearer {token}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    json=payload,
    timeout=30,
)

response.raise_for_status()
print(response.json())

HTTP / cURL

curl \
  -X POST \
  "https://merxalis.ru/integration/v1/catalog/products/upsert" \
  -H "Authorization: Bearer mrx_v1_..." \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 8a91584c-470d-4f44-b985-2a3d16432e54" \
  -d '{
    "items": [
      {
        "client_ref": "00125",
        "internal_code": "00125",
        "barcodes": ["4673752160115"]
      }
    ]
  }'

Версионирование

Текущий контракт находится в пространстве /integration/v1. Совместимые расширения могут добавляться в v1. Несовместимое изменение публичного контракта требует новой основной версии, например /integration/v2.

Статический файл OpenAPI фиксируется только после прохождения предрелизной проверки фактического контракта.

История изменений

Версия Состояние
v1 PREPUBLIC Организационный каталог, простая модель API-ключей, массовая и полная синхронизация, курсор изменений каталога, связи с маркетплейсами и чтение операционных данных.