Перед началом. Для обмена данными нужны активная организация продавца, подключённая интеграция и доступ для выбранной среды. Известные ограничения перечислены ниже. Значения в угловых скобках — заполнители, не реальные идентификаторы или ключи.
Как проверять запросы. Выполняйте примеры из сервера своей интеграции. API Reference служит справочником: сессия кабинета продавца не переносится в документацию. Для ERP нужен отдельный машинный токен с DPoP или mTLS; приватные ключи и токены остаются в вашей системе.
1. Подготовьте организацию
Действие администратора продавца
Нужны организация продавца со статусом active, право управлять её интеграциями, ID магазина, актуальная категория товара и ID склада. Проверьте статус организации через getSellerOrganization. Пока организация проходит регистрацию (onboarding), можно подготовить подключение и публичный ключ; обмен данными начнётся после завершения проверки магазина. Создание интеграции и учётных данных выполняет уполномоченный продавец со своей seller-сессией; выпуск учётных данных требует подтверждения владельца ключом доступа. Машинный токен принадлежит одной организации; он не заменяет административную сессию.
Базовый адрес запросов продавца — https://api.byme.my/seller/v1. Для каждого запроса передавайте X-Request-Id и W3C traceparent. Для записи используйте новый Idempotency-Key на новое намерение и тот же ключ при точном повторе тела. Ответы об ошибках разбирайте как application/problem+json, сохраняя request_id.
2. Создайте и активируйте интеграцию
Действие администратора продавца
Создайте интеграцию операцией createSellerIntegration (POST /organizations/{organization_id}/integrations). Запрашивайте только нужные возможности. callback_origin должен быть HTTPS origin под вашим контролем. Проверьте полученный integration_id и состояние через getSellerIntegration, затем вызовите activateSellerIntegration с причиной. Активация включает выдачу машинных токенов только после подтверждения issuer.
POST /seller/v1/organizations/<organization_id>/integrations
Authorization: Bearer <seller-role-access-token>
Idempotency-Key: <unique-key>
Content-Type: application/json
{
"type": "erp",
"environment": "production",
"callback_origin": "https://merchant.example",
"capabilities": ["catalog_read", "catalog_write", "inventory_write", "fulfillment_read", "fulfillment_write"]
}
POST /seller/v1/organizations/<organization_id>/integrations/<integration_id>/activation
Authorization: Bearer <seller-role-access-token>
Idempotency-Key: <another-unique-key>
Content-Type: application/json
{"reason":"Merchant integration ready"}
Получение интеграции возвращает сильный ETag. Если меняете её параметры через PATCH, отправляйте именно этот ETag в If-Match; при 409 или 412 сначала перечитайте состояние.
3. Зарегистрируйте публичный ключ
Действие администратора продавца и интегратора
Сгенерируйте отдельную пару P-256 в вашей системе. Приватный ключ никогда не передавайте ByMe. Операция createSellerIntegrationCredential принимает только публичные координаты JWK для DPoP. resource_scope.organization_id должен совпадать с путём и интеграцией. Сейчас машинный доступ активируется только для всей организации: массивы store_ids, warehouse_ids, market_codes должны быть пустыми, а field_allowlist — ["/"]. Подмножество возможностей учётных данных не может расширять возможности интеграции.
POST /seller/v1/organizations/<organization_id>/integrations/<integration_id>/credentials
Authorization: Bearer <seller-role-access-token>
Idempotency-Key: <unique-key>
Content-Type: application/json
{
"environment": "production",
"sender_constraint": "dpop",
"expires_at": "<future-rfc3339-time>",
"resource_scope": {
"organization_id": "<organization_id>",
"store_ids": [], "warehouse_ids": [], "market_codes": [],
"capabilities": ["catalog_read", "catalog_write", "inventory_write", "fulfillment_read", "fulfillment_write"],
"field_allowlist": ["/"]
},
"public_key_jwk": {"kty":"EC", "crv":"P-256", "x":"<base64url-x>", "y":"<base64url-y>"}
}
Для mTLS вместо DPoP отправьте публичный сертификат в client_certificate_pem и используйте https://identity-mtls.byme.my/oauth2/token для токена и отдельные catalog-mtls.byme.my и fulfillment-mtls.byme.my для соответствующих ресурсов. Клиентский приватный ключ остаётся у интегратора. Не смешивайте оба режима в одних учётных данных.
4. Получите короткий машинный токен
Действие интегратора
Для DPoP отправьте client_credentials на POST https://api.byme.my/oauth2/token с зарегистрированным client_id, подписанным ES256 private_key_jwt assertion и свежим DPoP proof для метода POST и именно этого публичного URL. В assertion iss и sub равны credential ID, aud — полному URL токена, jti уникален, а iat/exp ограничены пятью минутами. scope содержит только нужные разрешённые seller scopes. Токен живёт не более 900 секунд, refresh token не выдаётся.
Соответствие возможностей и scopes: catalog_read → seller:read-seller-shop-items, catalog_write → seller:upsert-seller-shop-items, inventory_write → seller:replace-seller-shop-inventory, fulfillment_read → seller:read-seller-shop-fulfillment-events, fulfillment_write → seller:create-seller-shop-fulfillment-events. Перечислите выбранные scopes через пробел, затем URL-кодируйте значение формы.
Ниже приведены примеры для сервера интеграции. Файлы с токенами, assertion и proof создавайте с закрытыми правами; команды сохраняют ответы в файлы и не печатают секретные значения.
# DPoP: assertion и proof уже подписаны вашим сервисом; каждый proof одноразовый.
set -euo pipefail
umask 077
RUN_DIR="$(mktemp -d)"
trap 'rm -rf "$RUN_DIR"' EXIT
TOKEN_RESPONSE_FILE="$RUN_DIR/token-response.json"
ACCESS_TOKEN_FILE="$RUN_DIR/access-token"
printf 'DPoP: %s\n' "$(cat "$DPoP_TOKEN_PROOF_FILE")" > "$RUN_DIR/token.headers"
curl --fail-with-body --silent --show-error \
--request POST 'https://api.byme.my/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header "@$RUN_DIR/token.headers" \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CREDENTIAL_ID" \
--data-urlencode "scope=$SELLER_SCOPES" \
--data-urlencode 'client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer' \
--data-urlencode "client_assertion@${CLIENT_ASSERTION_FILE}" \
--output "$TOKEN_RESPONSE_FILE"
jq -er '.access_token' "$TOKEN_RESPONSE_FILE" > "$ACCESS_TOKEN_FILE"
# Создайте новый proof для этого метода и URL с ath полученного токена.
printf 'Authorization: DPoP %s\nDPoP: %s\n' \
"$(cat "$ACCESS_TOKEN_FILE")" "$(cat "$DPoP_RESOURCE_PROOF_FILE")" > "$RUN_DIR/resource.headers"
curl --fail-with-body --silent --show-error \
--request GET 'https://api.byme.my/seller/v1/organizations/<organization_id>/shop-integration/items' \
--header "@$RUN_DIR/resource.headers" \
--output "$RUN_DIR/items.json"
# mTLS: certificate binding is proved by the TLS connection.
set -euo pipefail
umask 077
RUN_DIR="$(mktemp -d)"
trap 'rm -rf "$RUN_DIR"' EXIT
TOKEN_RESPONSE_FILE="$RUN_DIR/token-response.json"
ACCESS_TOKEN_FILE="$RUN_DIR/access-token"
curl --fail-with-body --silent --show-error \
--cert "$CLIENT_CERT_FILE" --key "$CLIENT_KEY_FILE" \
--request POST 'https://identity-mtls.byme.my/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$CREDENTIAL_ID" \
--data-urlencode "scope=$SELLER_SCOPES" \
--output "$TOKEN_RESPONSE_FILE"
jq -er '.access_token' "$TOKEN_RESPONSE_FILE" > "$ACCESS_TOKEN_FILE"
# Для товаров используйте catalog-mtls; DPoP и client_assertion здесь не нужны.
printf 'Authorization: Bearer %s\n' "$(cat "$ACCESS_TOKEN_FILE")" > "$RUN_DIR/resource.headers"
curl --fail-with-body --silent --show-error \
--cert "$CLIENT_CERT_FILE" --key "$CLIENT_KEY_FILE" \
--request GET 'https://catalog-mtls.byme.my/seller/v1/organizations/<organization_id>/shop-integration/items' \
--header "@$RUN_DIR/resource.headers" \
--output "$RUN_DIR/items.json"
Для каждого DPoP-запроса создавайте новый proof с фактическими методом и публичным URL и с ath от access token. Для mTLS используйте тот же клиентский сертификат и ключ на token endpoint и на ресурсном host; не добавляйте заголовок DPoP или форму client_assertion. Повтор одного proof отвергается. Не записывайте токены, assertions и proofs в логи. Правила proof и binding — RFC 9449; формат client assertion — RFC 7523.
5. Синхронизируйте товары
Действие интегратора
upsertSellerShopItems принимает пакет товаров по external_item_id в рамках организации. SKU — бизнес-атрибут, не ключ идемпотентности. Укажите действующую категорию, цену в младших единицах строкой, валюту и фискальный код. Начинайте с draft и проверяйте результат каждого элемента; активный статус входящего товара не обходит модерацию и не делает карточку покупаемой.
PUT /seller/v1/organizations/<organization_id>/shop-integration/items
Authorization: DPoP <access-token>
DPoP: <fresh-resource-proof>
Idempotency-Key: <stable-key-for-this-batch>
Content-Type: application/json
{"items":[{
"external_item_id":"item-001", "seller_sku":"SKU-001",
"title":"Пример товара", "category_id":"<approved-category-id>",
"store_id":"<store-id>", "status":"draft",
"price_minor":"10000", "currency":"RUB", "tax_code":"vat20"
}]}
Сверьте результат через GET /organizations/{organization_id}/shop-integration/items/{external_item_id} или список с cursor pagination. Публикация listing требует отдельных реальных условий готовности, включая модерацию и данные продавца.
6. Передайте остатки
Действие интегратора
replaceSellerShopInventory устанавливает абсолютное доступное количество для пары товар/склад. Передайте время фактического состояния: более старые события игнорируются. Инкрементальный режим обновляет только указанные пары. Полный snapshot обнуляет отсутствующие пары только на последней странице и только если все строки приняты и expected_item_count совпадает с числом различных пар.
PUT /seller/v1/organizations/<organization_id>/shop-integration/inventory
Authorization: DPoP <access-token>
DPoP: <fresh-resource-proof>
Idempotency-Key: <stable-key-for-this-batch>
Content-Type: application/json
{"mode":"incremental","items":[{
"external_item_id":"item-001", "warehouse_id":"<warehouse-id>",
"quantity_available":"0", "occurred_at":"<current-rfc3339-time>"
}]}
Нулевой остаток не скрывает карточку, но делает предложение недоступным к покупке. Точный повтор должен использовать тот же ключ и то же тело; конфликт fingerprint — терминальная ошибка, а не повод послать новую запись без чтения состояния.
Читайте заказы и возвраты в ERP
Для чтения заказов явно включите order_read и fulfillment_read в интеграцию и новые учётные данные. Запрашивайте оба scope: seller:read-seller-shop-orders и seller:read-seller-shop-fulfillment-events. Для возвратов нужны отдельная capability return_read и scope seller:read-seller-shop-returns. Существующие ключи не получают новые права автоматически; общий seller:read эти операции не разрешает.
GET /seller/v1/organizations/<organization_id>/shop-integration/orders?limit=50
GET /seller/v1/organizations/<organization_id>/shop-integration/returns?limit=50
Заказы содержат коммерческий status, информационный payment_state и отдельно фактические сведения о выполнении. confirmed означает подтверждение заказа продавцом. Пока событие выполнения не получено, fulfillment_status и fulfillment_version отсутствуют: не подставляйте paid или версию 1. Возвраты содержат собственный статус процесса возврата и seller_order_id; значения returned в статусах выполнения нет. Контакты покупателя, адреса, суммы и свободные заметки не экспортируются.
Передавайте page.next_cursor без изменения, пока page.has_more истинно. Заказы упорядочены по времени обновления, возвраты — по requested_at. Для повторной сверки возврата используйте его ID или seller_order_id: время создания не меняется при дальнейшем движении возврата. snapshot_at обозначает время наблюдения страницы, а не гарантию свежести всех проекций. Параметр seller_order_id для точечного чтения заказа не совмещается с cursor.
Проверяйте доступность этих новых операций в выбранной среде после выкладки. Для DPoP используется https://api.byme.my/seller/v1. Отдельные mTLS-маршруты заказов и возвратов требуют активации DNS, сертификатов и listener; адреса catalog-mtls.byme.my и fulfillment-mtls.byme.my эти операции не обслуживают.
7. Сообщайте о выполнении оплаченного заказа
Действие интегратора
После получения настоящего оплаченного seller_order_id, подтверждённого платёжной системой, передайте событие collecting через createSellerShopFulfillmentEvents. Это подтверждает выполнение продавцом и не является способом выставить или переопределить платёжный статус: paid и completed выставляет система на основании платёжной истины. Далее используйте только разрешённые переходы для выбранной модели доставки и необходимые поля доказательств. Время occurred_at сохраняется как сообщённое время; сроки и переходы рассчитывает сервер. Статус returned принадлежит процессу возврата и появляется после его авторитетного результата.
POST /seller/v1/organizations/<organization_id>/shop-integration/fulfillment-events
Authorization: DPoP <access-token>
DPoP: <fresh-resource-proof>
Idempotency-Key: <stable-key-for-this-batch>
Content-Type: application/json
{"events":[{
"event_id":"<unique-event-id>", "seller_order_id":"<paid-seller-order-id>",
"status":"collecting", "occurred_at":"<current-rfc3339-time>"
}]}
Проверяйте результат через GET /organizations/{organization_id}/shop-integration/fulfillment-events?seller_order_id=.... Повтор event_id с теми же данными не создаёт новую запись; повтор с другим содержимым отклоняется. Отмена оплаченного заказа запускает полный возврат покупателю и не должна использоваться как тестовое событие.
8. Обрабатывайте сбои и жизненный цикл доступа
| Ответ | Действие |
|---|---|
| 401/403 | Проверьте срок токена, DPoP proof, организацию, capability и состояние интеграции. Не повторяйте старый proof. |
| 409/412 | При fingerprint conflict не меняйте тело под прежним ключом; при устаревшем ETag перечитайте ресурс. |
| 429 | Учитывайте Retry-After; повторяйте ту же операцию с прежним ключом и телом, затем сверяйте авторитетное состояние. |
| 501/503 | Сверьте доступность операции ниже. Не повторяйте неподдерживаемую возможность в цикле; при временном 503 следуйте Retry-After, если он есть. |
При смене ключа используйте credential rotation с ограниченным временем перекрытия. При компрометации отзовите credential или интеграцию. Отзыв интеграции инвалидирует все её машинные токены. Для разбора ошибки передавайте поддержке продавца request_id и время, но не токен, приватный ключ или персональные данные.
Требования KYB
В текущем контракте required_actions ответов getSellerKybStatus, updateSellerKybProfile и createSellerKybSubmission содержит SellerKybRequiredAction: action_id, label, required. Это указания заполнить KYB или фискальный профиль; срок временного auth challenge к ним не применяется. После выполнения перечитайте статус. Изменение схемы одобрено владельцем API 28 сентября 2026; проверка новой версии в production ещё требуется.
Подписка в ответе организации
В текущем контракте business_subscription сохраняет ветку действительной подписки и допускает явное отсутствие данных: {"status":"unavailable","reason_code":"subscription_not_configured","retryable":false}. В этой ветке нет тарифа, периода, лимитов или прав подписки. Сначала проверьте состояние; не подставляйте бесплатный тариф или пробный период. Создание и чтение организации остаются доступны. Изменение одобрено владельцем API 28 сентября 2026; production-проверка новой проекции ещё требуется.
Вариант товара
getSellerProductVariant читает вариант рабочей ревизии PIM по организации и variant_id. Ответ содержит сохранённые sku_identifier_id, seller_sku, типизированные attributes, состояние и ревизию товара. gtin не означает проверку реестром. Предложения читайте отдельно. Неполные старые данные возвращают product_variant_metadata_incomplete.
Правила и цены предложений
- С seller-сессией прочитайте
GET /organizations/{organization_id}/pricing/production-workspace. Ответ включает default workspace,rules,automationиoffer_pricesнаsnapshot_at. Валюта каждой цены сохраняется отдельно. - Создайте черновое правило через
POST /organizations/{organization_id}/pricing/production-workspace/rulesсtarget,adjustment,floor(Money),priorityиschedule. Передайте Idempotency-Key; точный повтор не создаёт второе правило.predicateудалён из одобренной схемы. - Для проверки и активации используйте стандартные операции pricing workspace и его
workspace_id. Черновое правило не меняет действующие цены. Активация повторно проверяет актуальные данные и ограничения. - Для промокода перед активацией получите новый receipt через
simulateSellerPromotionдля конкретногоpromotion_id. Проверьте пустойguardrail_rejectionsи передайте егоsimulation_digest. Общий workspace digest не является receipt промокода.
Эти исправления проверены локально, включая PostgreSQL. Доступность новой версии в production проверяется отдельно после CI и выкладки. Машинные shop scopes не предоставляют права управления pricing или промо.
Текущие ограничения
Проверенные production-сценарии: upsert и чтение shop items, inventory batch и snapshot, события выполнения оплаченного заказа, DPoP/mTLS выпуск токена, replay и отзыв доступа. Offer contract, eligibility и tax quote также проверены реальными запросами после выкладки. Stock item detail проверен на QA SKU после incremental inventory feed с нулевым остатком: ответ 200 соответствует схеме. Warehouse detail вернул HTTP 200, но последующая проверка выявила несовпадение тела с контрактом; исправление требует новой выкладки. Налоговая политика проверена только на изолированной QA-организации; это не подтверждает ставки для реальных продавцов. Авторизованный проход всех 144 GET-операций и последующие проверки выявили следующие ещё недоступные возможности общего Seller OpenAPI:
| Ответ | Операции | Как действовать |
|---|---|---|
| 501 | Discount allocation. | Проверяйте фактическую доступность перед подключением. Не считайте описание в OpenAPI подтверждением запуска. |
| 503 | Catalog product aggregate (ожидает runtime-проверки), product variant (новая проекция ожидает выкладки), media, brand claim, certificate, generation job, authenticity policy; stock item detail для старых записей без SKU; ads entities; creator applications и catalog; business subscription и invoices; demand forecast; first-party finance. | Эти пути пока не подходят для обязательного сценария интеграции. Stock item требует сохранённого SKU: текущая цепочка catalog → inventory проверена, но старые записи без идентификатора SKU возвращают 503. Повторяйте только подтверждённый временный сбой. |
Список описывает состояние последней production-проверки, а не бессрочное обещание. Сверяйте доступность нужной операции перед внедрением. Нормативные схемы и точные статусы смотрите в Seller OpenAPI и Core OpenAPI.