マーチャント API:SKU、仕入れの事前登録、深圳倉庫の在庫を自社システムに連携
Shopee、Coupang、momo に出店している事業者向けです。出品時に作成した商品バーコードを API で送信し、仕入れ時には追跡番号と内容物を事前登録します。荷物が深圳倉庫に届くと作業指示書が自動発行され、ラベル貼付と一点ずつのスキャン・棚入れが行われます。在庫と差異はリアルタイムで返されます。
法人・事業者
利用対象(台湾の 8 桁の統一編号が必要)
200 件
SKU の 1 回あたりの一括登録上限
WO-SK
入荷時にラベル貼付の作業指示書を自動発行
60 回/分
API キーごとのデフォルトのレート制限
1 サービス概要
第1期では「商品と入庫」を提供します。SKU の作成から、商品が深圳倉庫で棚入れされて在庫になるまでをカバーします。
現在できること
- SKU を一括で作成・更新します(自社の
seller_skuを基準とします)。色・サイズごとに個別の商品バーコードを設定し、Shopee/Coupang/momo の商品バリエーション番号に紐づけます。 - 11 桁の関税分類番号から輸入規制を自動照合し、商品検査や許可が必要な商品、輸入できない商品にフラグを付けます。
- 仕入れ時に追跡番号と箱ごとの内容物を事前登録します。荷物が深圳倉庫に届くと WO-SK ラベル貼付作業指示書が自動発行され、倉庫で一点ずつラベルを貼付し、スキャンして棚入れします。
- 倉庫別在庫と在庫履歴を照会し、入荷、入庫完了、数量差異、在庫変動を webhook でリアルタイムに受け取れます。
入庫フロー
- SKU の作成:商品バーコード、バリエーション、申告品名、関税分類番号を送信します。
- 入庫予定の登録:追跡番号と各 SKU の予定数量を送信します。
- 深圳倉庫への入荷:追跡番号をスキャンすると WO-SK 作業指示書が自動で発行・印刷されます。
- ラベル貼付・棚入れ:倉庫が商品バーコードを印刷し、一点ずつ貼付してスキャンで数量をカウントします。
- 入庫完了:実際に受領した数量が深圳倉庫の在庫に計上され、破損品は別途計上されます。差異は自社システムに通知されます。
今後予定している機能
一括出荷オーダー、申告規定に基づいて自動でグループ化される出荷バッチ、桃園倉庫での事前在庫配置・仕分け・プラットフォーム配送ラベル。提供開始時に本ページでお知らせします。
2 申請と API キー
マーチャント API は登記済みの事業者のみ利用でき、各 API キーは承認済みのマーチャントアカウント 1 つに紐づきます。
利用開始の手順
- 会員センターで「法人」の申告者を追加し、8 桁の統一編号を入力します。
- HowBridge カスタマーサポートにマーチャント API の利用開始を申請してください。審査で承認されると API キーが発行されます。
- API キーは一度しか表示されません。サーバー側の環境変数に保存し、ブラウザやアプリには含めないでください。
- webhook を使う場合は、まず会員センターの API ページで URL を設定・検証してから、マーチャントイベントを購読してください。
Authorization: Bearer <APIキー> を使用します。一般会員がアプリやウェブサイトにログインして発行されたトークンでは、マーチャント 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 はフィールドごとの詳細です。唯一の例外は API キーがない、または無効な場合で、HTTP 401、body は {"message": "Unauthenticated."} になります。
{
"success": false,
"error": {
"code": "VALIDATION_FAILED",
"message": "…",
"errors": [
{ "code": "TRACKING_IN_USE", "field": "packages.0.tracking_no", "message": "…" }
]
}
}
レート制限
API キーごとに毎分 60 回、1 日 5,000 回です(高利用量プランは毎分 300 回、1 日 50,000 回)。一括エンドポイントは 1 回の呼び出しを 1 回として数えます。リアルタイムのデータが必要な場合は、ポーリングせずに webhook を購読してください。
| レスポンスヘッダー | 説明 |
|---|---|
X-RateLimit-Limit | 1 分あたりの上限 |
X-RateLimit-Remaining | この 1 分間の残り回数 |
X-RateLimit-Limit-DayX-RateLimit-Remaining-Day | 1 日の上限と残り回数 |
Retry-After | 上限を超えた場合に、再試行できるまでの秒数 |
べき等性(Idempotency-Key)
書き込みリクエストには Idempotency-Key ヘッダーを付けられます(8–128 文字、英数字と _-:.)。ネットワークのタイムアウト後に同じキー・同じ内容で再送すると、初回のレスポンスが返り、ヘッダー Idempotent-Replayed: true が付きます。同じキーで内容を変えると 422 が返ります。記録は 24 時間保持されます。
一括処理のレスポンス
一括エンドポイントは 1 件ごとに結果を返します。すべて成功した場合は 200、一部が失敗した場合は 207、すべて失敗した場合は 422 です。各件には index、status(created/updated/failed)と失敗理由が含まれます。
識別子に使える文字
seller_sku には英数字と ._- のみ使用できます(1–64 文字)。商品バーコードではさらに / と + も使用できます(3–64 文字)。大文字と小文字は区別されません。
4 商品 SKU
SKU は自社の seller_sku を一意のキーとします。同じ seller_sku を再送すると更新として扱われ、送信したフィールドのみが変更されます。
SKU の一括作成・更新
POST/api/v1/merchant/skus/batch
1 回あたり最大 200 件です。各件は個別に処理されるため、1 件が失敗しても他の件には影響しません。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
seller_sku | string | 必須 | 自社の SKU 番号。例:Shopee の商品バリエーションの SKU。 |
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 | 任意 | 1 点あたりの重量(グラム)。 |
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
送信したリストで既存の紐づけをすべて置き換えます。同じプラットフォームのバリエーションを、2 つの SKU に同時に紐づけることはできません。
商品バーコードラベルのダウンロード
GET/api/v1/merchant/skus/{seller_sku}/label.pdf?qty=10
40×30mm のラベル PDF を返します。qty は枚数です(1–1000)。深圳倉庫でのラベル貼付時にも同じラベルを印刷します。出荷前に自社でラベルを貼りたい場合にご利用ください。
5 入庫予定の登録
仕入先が発送したら、追跡番号と内容物を事前登録します。1 つの入庫オーダーに複数の追跡番号を含めることができ、各追跡番号の下に SKU と数量を記載します。
入庫オーダーの作成
POST/api/v1/merchant/inbound-orders
オーダー全体で検証し、エラーが 1 つでもあれば作成されません。1 つの追跡番号が同時に属せるのは、処理中の入庫オーダー 1 件のみです。同じ荷物内で重複した SKU は数量が合算されます。
| フィールド | 型 | 必須 | 説明 |
|---|---|---|---|
reference_no | string | 必須 | 自社の発注番号または入庫オーダー番号。同一マーチャント内で一意である必要があります(英数字と ._-/)。 |
supplier_order_no | string | 任意 | 仕入先の注文番号。例:1688 の注文番号。 |
warehouse_code | string | 任意 | 入庫倉庫。現在は SZ(深圳倉庫)のみ受け付けます。 |
notes | string | 任意 | 備考(最大 1,000 文字)。 |
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 カーソルで次のページを取得し(1 回あたり最大 500 件)、レスポンスの meta.next_after_id を保存しておけば、続きから取得して照合できます。
7 Webhook イベント
イベントが発生すると指定の URL へ通知がプッシュされるため、ポーリングは不要です。
設定方法
- 会員センターの API ページで webhook URL を設定し(https のみ)、所有権の検証を完了してください。エンドポイントは HTTP 200 を返し、body を
{"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=署名 が含まれます。webhook secret を使って「タイムスタンプ + . + 元の body」の HMAC-SHA256 を計算して v1 と比較し、5 分より古いタイムスタンプは拒否してください。同じイベントの再試行では delivery_id が変わらないため、重複排除に使用できます。
2xx 以外のレスポンスの場合、1 分後、5 分後、30 分後、2 時間後、6 時間後に再試行します。20 回連続で失敗すると自動的に無効化され、会員センターで再設定が必要になります。
// 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 | — | API キーがない、無効、または期限切れです(body は {"message": "Unauthenticated."})。 |
| 403 | MERCHANT_TOKEN_REQUIRED | このトークンにはマーチャント API の権限がありません(例:一般会員のログインで発行されたトークン)。 |
| 403 | MERCHANT_NOT_APPROVEDMERCHANT_SUSPENDED | アカウントがマーチャントとして承認されていないか、マーチャントが停止されています。 |
| 403 | APP_SUSPENDEDAPP_REVOKEDAPP_NOT_FOUND | API キーに対応する 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 コード例
以下のコード例はサーバー側で実行してください。API キーをフロントエンドのコードに含めないでください。
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。