API для продавцов: подключите SKU, заявки на приёмку закупок и остатки склада в Шэньчжэне к своей системе
Для компаний, торгующих на Shopee, Coupang и momo. Передавайте через API штрихкоды товаров, созданные при размещении карточек, при закупке заранее сообщайте трек-номера и содержимое, а при поступлении груза на склад в Шэньчжэне автоматически создаётся наряд, товары маркируются, поштучно сканируются и размещаются на хранение — остатки и расхождения передаются вам в реальном времени.
Компании
Кто может подключиться (нужен 8-значный налоговый номер Тайваня)
200
Максимум SKU в одном пакетном запросе
WO-SK
Наряд на маркировку при поступлении
60 / мин
Лимит запросов на ключ по умолчанию
1 Обзор
Этап 1 охватывает «товары и приёмку»: от создания SKU до размещения товара на складе в Шэньчжэне в виде остатков.
Что уже доступно
- Массово создавать и обновлять SKU (ключ — ваш
seller_sku) с отдельным штрихкодом товара для каждого цвета и размера и привязывать их к вариантам товаров на Shopee / Coupang / momo. - Автоматически проверять требования к ввозу по 11-значному коду таможенного тарифа и отмечать товары, которым нужна обязательная проверка или разрешение либо ввоз которых запрещён.
- При закупке заранее сообщать трек-номера и содержимое каждой коробки; при поступлении на склад в Шэньчжэне автоматически создаётся наряд на маркировку WO-SK, и склад поштучно маркирует, сканирует и размещает товар.
- Запрашивать остатки по складам и журнал движения остатков, а также получать через webhook в реальном времени события о поступлении, завершении приёмки, расхождениях в количестве и изменении остатков.
Процесс приёмки
- Создание SKU: передайте штрихкоды товаров, варианты, наименования для декларации и коды тарифа.
- Заявка на приёмку: передайте трек-номера и ожидаемое количество по каждому SKU.
- Поступление на склад в Шэньчжэне: после сканирования трек-номера автоматически создаётся и печатается наряд WO-SK.
- Маркировка и размещение: склад печатает штрихкоды товаров, поштучно наклеивает их и сканирует для подсчёта.
- Приёмка завершена: фактически принятое количество зачисляется в остатки склада в Шэньчжэне, повреждённые единицы учитываются отдельно, а расхождения отправляются в вашу систему.
Планируемые функции
Массовые заказы на отгрузку, партии отгрузки с автоматической группировкой по правилам декларирования, а также заранее размещённые запасы, сортировка и транспортные этикетки маркетплейсов на складе в Таоюане. О запуске будет объявлено на этой странице.
2 Доступ и ключи
API для продавцов доступен только зарегистрированным компаниям; каждый ключ привязан к одобренному аккаунту продавца.
Как подключиться
- В личном кабинете добавьте декларанта типа «компания» и укажите 8-значный налоговый номер Тайваня.
- Свяжитесь со службой поддержки HowBridge, чтобы подключить API для продавцов; ключ выдаётся после одобрения.
- Ключ показывается только один раз. Храните его в переменной окружения на сервере и никогда не размещайте в браузере или приложении.
- Если нужны webhook, сначала настройте и подтвердите URL на странице API в личном кабинете, затем подпишитесь на события продавца.
Authorization: Bearer <ключ>. Токены, полученные при обычном входе в приложение или на сайт, не могут вызывать API для продавцов.Authorization: Bearer 12|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Accept: application/json
3 Общие правила
Эти правила действуют для всех эндпоинтов.
Base URL
Формат и язык
Запросы и ответы передаются в формате JSON. Сообщения об ошибках по умолчанию возвращаются на традиционном китайском; с заголовком Accept-Language: en — на английском. В логике программы всегда опирайтесь на error.code, который всегда на английском.
Структура ответа
При успехе возвращается {"success": true, "data": …, "meta": …}; при ошибке — {"success": false, "error": {"code", "message", "errors", "context"}}, где errors содержит сведения по каждому полю. Единственное исключение — отсутствующий или недействительный ключ: HTTP 401 с телом {"message": "Unauthenticated."}.
{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "…",
"errors": [
{ "code": "TRACKING_IN_USE", "field": "packages.0.tracking_no", "message": "…" }
]
}
}
Лимиты запросов
60 запросов в минуту и 5000 в сутки на ключ (на тарифе для высокой нагрузки — 300 в минуту и 50 000 в сутки); пакетный запрос считается за один. Для получения данных в реальном времени подпишитесь на webhook вместо периодического опроса.
| Заголовок ответа | Описание |
|---|---|
X-RateLimit-Limit | Лимит в минуту |
X-RateLimit-Remaining | Осталось запросов в текущей минуте |
X-RateLimit-Limit-DayX-RateLimit-Remaining-Day | Суточный лимит и остаток запросов |
Retry-After | Через сколько секунд можно повторить запрос после превышения лимита |
Идемпотентность (Idempotency-Key)
Запросы на запись принимают заголовок Idempotency-Key (8–128 символов: латинские буквы, цифры и _-:.). Если после сетевого тайм-аута повторить запрос с тем же ключом и тем же содержимым, вернётся первоначальный ответ с заголовком Idempotent-Replayed: true; тот же ключ с другим содержимым вернёт 422. Записи хранятся 24 часа.
Пакетные ответы
Пакетные эндпоинты возвращают результат по каждой записи: 200 — все успешно, 207 — часть с ошибками, 422 — все с ошибками. У каждой записи есть index, status (created / updated / failed) и причина ошибки.
Допустимые символы идентификаторов
seller_sku может содержать только латинские буквы, цифры и ._- (1–64 символа); штрихкод товара может также содержать / и + (3–64 символа). Регистр не учитывается.
4 SKU товаров
Уникальный ключ SKU — ваш seller_sku: повторная отправка того же seller_sku обновляет SKU и изменяет только переданные поля.
Массовое создание и обновление SKU
POST/api/v1/merchant/skus/batch
До 200 записей за запрос. Каждая запись обрабатывается независимо, ошибка в одной не влияет на остальные.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
seller_sku | string | Обязательно | Ваш код SKU, например артикул варианта товара на Shopee. |
product_name | string | Обязательно при создании | Название товара. SKU с одинаковым названием группируются в один товар. |
barcode | string | Необязательно | Штрихкод товара: по нему склад печатает этикетки и сканирует товар при размещении. У разных цветов и размеров штрихкоды должны различаться. Если штрихкода нет, оставьте поле пустым — система создаст системный штрихкод. Если длина превышает 16 символов, на этикетке печатается системный штрихкод. |
gtin | string | Необязательно | Международный штрихкод GTIN (8 / 12 / 13 / 14 цифр, контрольная цифра проверяется). Для варианта Shopee «у товара нет GTIN» передайте 00. |
spec | object | Необязательно | Характеристики варианта, например {"color": "чёрный", "size": "M"}, не более 5. |
declared_name_zhdeclared_name_en | string | Необязательно | Наименование для декларации (на китайском / английском): укажите материал и назначение, не пишите «образец» или «подарок». |
declared_unit_value | number | Необязательно | Заявленная стоимость единицы — ваша закупочная цена у поставщика, а не цена продажи на маркетплейсе. |
declared_currency | string | Необязательно | CNY, TWD или USD; обязательно, если указана стоимость единицы. |
hs_code | string | Необязательно | 11-значный код товарной классификации, по которому система проверяет требования к ввозу. |
origin_country | string | Необязательно | ISO-код страны происхождения, по умолчанию CN. |
weight_g | integer | Необязательно | Вес единицы (граммы). |
dimensions_cm | array | Необязательно | Длина, ширина и высота (сантиметры), например [20, 15, 3]. |
battery_type | string | Необязательно | none, contained (встроенный), packed (в комплекте), standalone (отдельный аккумулятор). |
channels | array | Необязательно | Привязки к товарам на маркетплейсах, не более 20: platform (shopee / coupang / momo / other), shop_id, item_id, model_id, platform_sku. |
Пример запроса (POST JSON)
curl -X POST https://0523.tw/api/v1/merchant/skus/batch \ -H "Authorization: Bearer $LUCKY_MERCHANT_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: sku-sync-20260917-001" \ -d '{ "items": [ { "seller_sku": "TEE-RED-S", "barcode": "4710000000011", "product_name": "Cotton T-shirt", "spec": { "color": "red", "size": "S" }, "declared_name_en": "Cotton knitted T-shirt", "declared_unit_value": 18.5, "declared_currency": "CNY", "hs_code": "61091000006", "weight_g": 160, "channels": [ { "platform": "shopee", "shop_id": "123456", "item_id": "2233", "model_id": "445566" } ] } ] }'
Ответ 200
{
"success": true,
"data": [
{
"index": 0,
"seller_sku": "TEE-RED-S",
"status": "created",
"sku": {
"seller_sku": "TEE-RED-S",
"barcode": "4710000000011",
"system_barcode": null,
"pick_code": "131999",
"hs_code": "61091000006",
"regulation": { "status": "ok", "import_codes": [], "reasons": [] },
"channels": [ { "platform": "shopee", "shop_id": "123456", "item_id": "2233", "model_id": "445566", "platform_sku": null } ]
}
}
],
"meta": { "summary": { "created": 1, "updated": 0, "failed": 0 } }
}
Проверка требований к ввозу (regulation.status)
| ok | Кодов требований к ввозу нет. |
| review_required | Требование распространяется только на часть товаров (например, C02 «часть товаров данной позиции подлежит обязательной проверке»); нужно уточнить по фактическому назначению товара. |
| formal_required | Действуют требования к ввозу (проверка, карантин, разрешения и т. п.); упрощённое декларирование использовать нельзя. |
| blocked | Товар из материкового Китая, запрещённый к ввозу (MW0, страна происхождения — материковый Китай); его нельзя включить в заявку на приёмку. |
| unclassified | Код тарифа ещё не указан, проверка невозможна. |
Список SKU
GET/api/v1/merchant/skus
Фильтры: seller_sku, barcode, regulation_status, updated_since (ISO 8601); пагинация — page / per_page (не более 100).
Один SKU
GET/api/v1/merchant/skus/{seller_sku}
Обновление привязок к маркетплейсам
PUT/api/v1/merchant/skus/{seller_sku}/channels
Переданный список полностью заменяет существующие привязки; один и тот же вариант товара на маркетплейсе нельзя привязать к двум SKU.
Скачать этикетки со штрихкодом
GET/api/v1/merchant/skus/{seller_sku}/label.pdf?qty=10
Возвращает PDF с этикетками 40×30 мм; qty — количество этикеток (1–1000). Склад в Шэньчжэне при маркировке печатает такие же этикетки; этот метод нужен, если вы хотите промаркировать товар самостоятельно до отправки.
5 Заявки на приёмку
После отправки закупки передайте трек-номера и содержимое посылок в заявке на приёмку. В одной заявке может быть несколько трек-номеров, и для каждого указываются SKU и количество.
Создать заявку на приёмку
POST/api/v1/merchant/inbound-orders
Заявка проверяется целиком: при любой ошибке ничего не создаётся. Трек-номер может одновременно входить только в одну активную заявку на приёмку; повторяющиеся SKU в одной посылке объединяются с суммированием количества.
| Поле | Тип | Обязательно | Описание |
|---|---|---|---|
reference_no | string | Обязательно | Номер вашего заказа на закупку или заявки на приёмку, уникальный в пределах продавца (латинские буквы, цифры и ._-/). |
supplier_order_no | string | Необязательно | Номер заказа у поставщика, например номер заказа на 1688. |
warehouse_code | string | Необязательно | Склад приёмки; сейчас принимается только SZ (склад в Шэньчжэне). |
notes | string | Необязательно | Примечание (не более 1000 символов). |
packages | array | Обязательно | Список посылок, не более 50. |
packages[].tracking_no | string | Обязательно | Трек-номер китайской курьерской службы. |
packages[].carrier | string | Необязательно | Код курьерской службы, например yto или sf. |
packages[].items | array | Обязательно | Содержимое посылки: seller_sku и qty, всего не более 500 строк на заявку. |
Пример запроса (POST JSON)
curl -X POST https://0523.tw/api/v1/merchant/inbound-orders \ -H "Authorization: Bearer $LUCKY_MERCHANT_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: po-20260917-0001" \ -d '{ "reference_no": "PO-20260917-0001", "supplier_order_no": "1688-3312456789", "packages": [ { "tracking_no": "YT1234567890123", "carrier": "yto", "items": [ { "seller_sku": "TEE-RED-S", "qty": 40 }, { "seller_sku": "TEE-RED-M", "qty": 60 } ] } ] }'
reference_no возвращает 409 INBOUND_REFERENCE_EXISTS, а в error.context.inbound_order_id передаётся id исходной заявки. Для безопасного повтора передавайте Idempotency-Key.Статусы заявки на приёмку
| created | Заявка создана, посылки ещё не поступили. |
| partially_arrived | Часть посылок поступила на склад в Шэньчжэне. |
| arrived | Все посылки поступили, идут маркировка и размещение. |
| completed | Размещение завершено, количество совпадает с заявкой. |
| completed_with_discrepancy | Завершено, но есть недостача, излишки или повреждения. |
| cancelled | Отменена. |
Статусы посылки
| awaiting_arrival | Ожидает поступления. |
| labeling | Поступила на склад, наряд создан, идут маркировка и размещение. |
| received | Размещение завершено. |
| mismatch | Принадлежность посылки, зафиксированная при поступлении, не совпадает с вашей заявкой; служба поддержки проводит проверку. |
| cancelled | Отменена или аннулирована; трек-номер освобождён. |
Список заявок на приёмку
GET/api/v1/merchant/inbound-orders
GET/api/v1/merchant/inbound-orders/{id}
Фильтры: status, reference_no, updated_since. Для каждой посылки возвращаются заявленное, фактически принятое и повреждённое количество, а также расхождение.
Отменить заявку на приёмку
POST/api/v1/merchant/inbound-orders/{id}/cancel
Отменить заявку можно, только пока ни одна посылка не поступила на склад; после отмены трек-номера можно снова указать в заявке.
6 Остатки
Остатки ведутся раздельно по складам: SZ — склад в Шэньчжэне, TY — склад в Таоюане (остатки склада в Таоюане станут доступны вместе с функциями отгрузки).
Запрос остатков
GET/api/v1/merchant/inventory?warehouse_code=SZ
Фильтры: warehouse_code и seller_sku[] (не более 200).
on_hand | Количество на складе. |
reserved | Количество, зарезервированное под заказы. |
available | Доступное количество = на складе − зарезервировано. |
damaged | Количество повреждённых единиц; отгрузке не подлежат. |
Ответ 200
{
"success": true,
"data": [
{ "seller_sku": "TEE-RED-S", "barcode": "4710000000011", "warehouse_code": "SZ",
"on_hand": 38, "reserved": 0, "available": 38, "damaged": 2, "updated_at": "2026-09-17T15:20:11+08:00" }
],
"meta": { "total": 1, "page": 1, "per_page": 100, "last_page": 1 }
}
Журнал движения остатков
GET/api/v1/merchant/inventory/movements?after_id=0&limit=200
Записи о движении только добавляются и никогда не изменяются. Листайте вперёд с курсором after_id (не более 500 записей за запрос) и сохраняйте meta.next_after_id из ответа, чтобы продолжить сверку.
7 События webhook
События отправляются на ваш URL в момент их возникновения — опрашивать API не нужно.
Настройка
- Укажите URL для webhook на странице API в личном кабинете (только https) и пройдите проверку владения: ваш эндпоинт должен ответить HTTP 200 с телом
{"challenge": "полученное значение"}. - Вызовите
PUT /api/v1/merchant/webhook/events, чтобы подписаться на события продавца. Последующая смена URL в личном кабинете не сбрасывает эти подписки.
curl -X PUT https://0523.tw/api/v1/merchant/webhook/events \ -H "Authorization: Bearer $LUCKY_MERCHANT_KEY" \ -H "Content-Type: application/json" \ -d '{"events": ["inbound.arrived", "inbound.received", "inbound.discrepancy", "inventory.changed"]}'
Список событий
sku.regulation_flagged | Результат проверки требований к ввозу для SKU изменился на «требует уточнения», «требуется полная таможенная декларация» или «ввоз запрещён». |
inbound.arrived | Посылка поступила на склад в Шэньчжэне, наряд создан. |
inbound.mismatch | Принадлежность посылки, зафиксированная при поступлении, не совпадает с заявкой; служба поддержки проводит проверку. |
inbound.received | Размещение посылки завершено; содержит заявленное, фактически принятое и повреждённое количество по каждому SKU. |
inbound.discrepancy | Размещённое количество отличается от заявленного или есть повреждения (отправляется одновременно с inbound.received). |
inventory.changed | Остатки изменились; содержит актуальные остатки затронутых SKU. |
inbound.received
{
"event": "inbound.received",
"delivery_id": "5b0f1c2e-8f3a-4d7e-9c21-0a6b2d4e8f10",
"created_at": "2026-09-17T15:20:11+08:00",
"data": {
"inbound_order_id": 128,
"reference_no": "PO-20260917-0001",
"order_status": "completed_with_discrepancy",
"tracking_no": "YT1234567890123",
"work_order": "WO-SK-315",
"warehouse_code": "SZ",
"items": [
{ "seller_sku": "TEE-RED-S", "expected_qty": 40, "received_qty": 38, "damaged_qty": 2, "difference": 0 },
{ "seller_sku": "TEE-RED-M", "expected_qty": 60, "received_qty": 59, "damaged_qty": 0, "difference": -1 }
],
"received_at": "2026-09-17T15:20:10+08:00"
}
}
Проверка подписи
Каждая отправка содержит X-Lucky-Event, X-Lucky-Delivery-Id и X-Lucky-Signature: t=метка_времени,v1=подпись. Вычислите HMAC-SHA256 от «метка времени + . + исходное тело» с вашим webhook secret, сравните результат с v1 и отклоняйте метки времени старше 5 минут. При повторных отправках одного события delivery_id не меняется, поэтому его можно использовать для устранения дублей.
При ответе, отличном от 2xx, отправка повторяется через 1 минуту, 5 минут, 30 минут, 2 часа и 6 часов; после 20 неудачных попыток подряд webhook автоматически отключается, и его нужно заново настроить в личном кабинете.
// PHP $body = file_get_contents('php://input'); $header = $_SERVER['HTTP_X_LUCKY_SIGNATURE'] ?? ''; parse_str(str_replace(',', '&', $header), $sig); // ['t' => '1789…', 'v1' => 'ab12…'] $expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, getenv('LUCKY_WEBHOOK_SECRET')); if (! hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) ($sig['t'] ?? 0)) > 300) { http_response_code(400); exit; } $event = json_decode($body, true); // de-duplicate by $event['delivery_id'] http_response_code(200);
8 Коды ошибок
error.code всегда на английском. Ниже приведены частые ошибки.
| HTTP | error.code | Описание |
|---|---|---|
| 401 | — | Ключ не передан, недействителен или истёк (тело: {"message": "Unauthenticated."}). |
| 403 | MERCHANT_TOKEN_REQUIRED | У этого токена нет доступа к API для продавцов (например, токен, полученный при обычном входе в аккаунт). |
| 403 | MERCHANT_NOT_APPROVEDMERCHANT_SUSPENDED | Аккаунт ещё не одобрен как продавец, или продавец приостановлен. |
| 403 | APP_SUSPENDEDAPP_REVOKEDAPP_NOT_FOUND | API-приложение, к которому относится ключ, приостановлено или отозвано. |
| 422 | VALIDATION_FAILEDPRODUCT_NAME_REQUIRED | Неверный формат данных; подробности по полям — в error.errors. |
| 422 | BATCH_TOO_LARGE | Количество записей в пакете превышает лимит. |
| 207 / 409 | SKU_BARCODE_DUPLICATESKU_BARCODE_CONFLICT | Штрихкод товара уже используется другим SKU или совпадает с системным штрихкодом либо кодом комплектации другого SKU. |
| 207 / 422 | GTIN_INVALIDHS_CODE_NOT_FOUND | Неверная контрольная цифра GTIN, или код тарифа не существует. |
| 404 / 422 | SKU_NOT_FOUNDSKU_IMPORT_BLOCKED | SKU не найден, или товар запрещён к ввозу и его нельзя включить в заявку на приёмку. |
| 409 | INBOUND_REFERENCE_EXISTS | Заявка на приёмку с таким номером уже существует. |
| 422 | TRACKING_IN_USETRACKING_FORECASTED_BY_OTHERTRACKING_ALREADY_WAREHOUSEDTRACKING_NOT_AVAILABLE | Трек-номер уже входит в активную заявку на приёмку, уже заявлен другим клиентом или уже поступил на склад на имя другого клиента. |
| 409 | INBOUND_NOT_CANCELLABLE | Посылка уже поступила на склад, заявку на приёмку отменить нельзя. |
| 400 / 409 / 422 | IDEMPOTENCY_KEY_INVALIDIDEMPOTENCY_IN_PROGRESSIDEMPOTENCY_KEY_REUSED | Неверный формат Idempotency-Key, ключ использован с другим содержимым, или предыдущий запрос ещё обрабатывается. |
| 409 | CONFLICT_RETRY | Эту запись сейчас изменяет другой запрос; повторите попытку чуть позже. |
| 429 | RATE_LIMIT_EXCEEDED | Лимит запросов превышен; подождите время, указанное в Retry-After, и повторите запрос. |
9 Примеры кода
Запускайте приведённые ниже примеры на сервере и никогда не размещайте ключ во фронтенд-коде.
use Illuminate\Support\Facades\Http; use Illuminate\Support\Str; $api = Http::withToken(config('services.lucky.merchant_key')) ->acceptJson() ->baseUrl('https://0523.tw/api/v1/merchant') ->timeout(20); // 1) Sync SKUs (up to 200 per request) $res = $api->withHeaders(['Idempotency-Key' => (string) Str::uuid()]) ->post('/skus/batch', ['items' => $items]); foreach ($res->json('data') as $row) { if ($row['status'] === 'failed') { logger()->warning('SKU failed', $row['errors']); } } // 2) Forecast an inbound order $order = $api->withHeaders(['Idempotency-Key' => 'po-' . $po->id]) ->post('/inbound-orders', [ 'reference_no' => $po->number, 'packages' => [[ 'tracking_no' => $po->tracking_no, 'items' => [['seller_sku' => 'TEE-RED-S', 'qty' => 40]], ]], ])->throw()->json('data'); // 3) Read Shenzhen stock $stock = $api->get('/inventory', ['warehouse_code' => 'SZ'])->json('data');
// Node.js 18+ (server side only) import { randomUUID } from 'node:crypto'; const base = 'https://0523.tw/api/v1/merchant'; const headers = { Authorization: `Bearer ${process.env.LUCKY_MERCHANT_KEY}`, 'Content-Type': 'application/json', Accept: 'application/json', }; const res = await fetch(`${base}/skus/batch`, { method: 'POST', headers: { ...headers, 'Idempotency-Key': randomUUID() }, body: JSON.stringify({ items }), }); const { data, meta } = await res.json(); console.log(meta.summary); // { created, updated, failed } const stock = await fetch(`${base}/inventory?warehouse_code=SZ`, { headers }).then(r => r.json());
import os, uuid, requests base = "https://0523.tw/api/v1/merchant" session = requests.Session() session.headers.update({ "Authorization": f"Bearer {os.environ['LUCKY_MERCHANT_KEY']}", "Accept": "application/json", }) r = session.post(f"{base}/inbound-orders", headers={"Idempotency-Key": "po-20260917-0001"}, json={ "reference_no": "PO-20260917-0001", "packages": [{"tracking_no": "YT1234567890123", "items": [{"seller_sku": "TEE-RED-S", "qty": 40}]}], }, timeout=20) if r.status_code == 409: existing_id = r.json()["error"]["context"]["inbound_order_id"] else: r.raise_for_status()
10 Техподдержка
Если при интеграции возникли проблемы, сообщите время запроса, эндпоинт и error.code — так нам будет проще найти причину.
Официальный аккаунт LINE @0523tw
Техническая почта howyunqisoftware@gmail.com
Версия v1, этап 1 (2026-09-17): SKU товаров, заявки на приёмку, маркировка и размещение на складе в Шэньчжэне, запрос остатков, webhook.