在庫更新プログラムの準備(Ver.2)【汎用】 ID:58491
※在庫更新プログラムの準備については、サポート対象外です。
本システムから店舗へ在庫数を更新するために必要な在庫更新プログラムを準備するための操作手順です。
本システムは、在庫更新時にユーザーが指定したURLへHTTPリクエストを送信します。
店舗側では、このリクエストを受信するWebhookエンドポイントを実装してください。
Ver.1から切り替えを行う場合
Ver.2にて連携を行う場合、店舗設定にて「在庫更新APIのバージョン」設定を「Ver.2」に変更してください。
1.概要
- 通信方式:HTTP POST
- Content-Type:application/json
- Content-Encoding:なし(非圧縮)
- 文字コード:UTF-8
- 通信頻度:在庫更新イベントに応じて送信(目安:数分間隔)
2.HTTPヘッダ
| ヘッダ名 | 必須 | 説明 |
|---|---|---|
| X-Store-Account | ◯ | ストアアカウント |
| X-Request-Timestamp | ◯ | UNIXタイムスタンプ(秒) |
| X-Signature | ◯ | リクエスト検証用の署名 |
3.リクエストボディ
JSON形式で送信されます。1回の通信につき、最大1000商品まで連携されます。
[
{
"goods_id": "goods1",
"stock": {
"free_quantity": 300,
"advance_order_free_quantity": 0
}
},
{
"goods_id": "goods2",
"stock": null
}
]
空配列の場合は、「疎通テスト」であることを表します。
後述する検証ルールに沿っている通信であれば、HTTPステータスコード200を、そうでなければ200以外を返してください。
[]
4.フィールド仕様
| goods_id |
|
| stock |
|
| free_quantity |
|
| advance_order_free_quantity |
|
5.署名生成
以下の文字列を対象にHMAC-SHA256で署名を生成します。
{timestamp}\n{store_account}\n{raw_body}
\nはLF(改行コード)を表しますraw_bodyはHTTPリクエストボディをそのまま使用します
6.署名例(擬似コード)
signature = HMAC_SHA256(
"{timestamp}\n{store_account}\n{raw_body}",
secret
)
7.検証ルール
受信側では以下を確認してください。
- 署名が一致すること
X-Request-Timestampが現在時刻±5分以内であること- リクエストボディを改変していないこと
8.注意事項
署名検証する際は、HTTPリクエストボディを再フォーマット等せず、そのまま使用してください。
- 改行コードはLF(
\n)を使用してください - 文字コードはUTF-8を前提とします
- 複数拠点が設定されている場合、最大在庫数の拠点の値が送信されます
- Ver.1と同等の在庫数を使用する場合は以下を利用してください
free_quantity + advance_order_free_quantity
9.レスポンス
受信側は以下のレスポンスを返してください。
- HTTPステータス:200
失敗した場合は、200以外のレスポンスを返してください。
レスポンスコードは、在庫連携履歴に表示されます。
10.リトライについて
HTTPステータスが200以外の場合、リクエストは再送される場合があります。
11.通信要件
送信先のサーバーはHTTPSである必要があります。
また、TLS1.2以上に対応している必要があります。
12.セキュリティに関する注意事項
送信元のIPアドレスは変更される可能性があります。
IPアドレスによるアクセス制限には依存しないでください。
リクエストの正当性を確認する場合は、HMAC署名(X-Signature)を使用して検証してください。
13.実装例(PHP)
<?php
// =========================
// ■ 設定(ここを変更)
// =========================
// ストアアカウントごとのシークレットキー
$secrets = [
'store_a' => 'your-secret-key-for-store-a',
'store_b' => 'your-secret-key-for-store-b',
];
// 許容する時間差(秒)※5分
$allowedTimeDrift = 300;
// =========================
// ■ リクエスト取得
// =========================
$storeAccount = $_SERVER['HTTP_X_STORE_ACCOUNT'] ?? null;
$timestamp = $_SERVER['HTTP_X_REQUEST_TIMESTAMP'] ?? null;
$signature = $_SERVER['HTTP_X_SIGNATURE'] ?? null;
$rawBody = file_get_contents('php://input');
// =========================
// ■ ① 必須チェック
// =========================
if (is_null($storeAccount) || is_null($timestamp) || is_null($signature)) {
http_response_code(400);
echo "Missing required headers";
exit;
}
// =========================
// ■ ② アカウント検証
// =========================
if (!isset($secrets[$storeAccount])) {
http_response_code(403);
echo "Invalid store account";
exit;
}
$secret = $secrets[$storeAccount];
// =========================
// ■ ③ タイムスタンプ検証
// =========================
if (!ctype_digit($timestamp)) {
http_response_code(400);
echo "Invalid timestamp";
exit;
}
$timestamp = (int)$timestamp;
$now = time();
if (abs($now - $timestamp) > $allowedTimeDrift) {
http_response_code(401);
echo "Request expired";
exit;
}
// =========================
// ■ ④ 署名検証
// =========================
$expectedSignature = hash_hmac(
'sha256',
"{$timestamp}\n{$storeAccount}\n{$rawBody}",
$secret
);
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
echo "Invalid signature";
exit;
}
// =========================
// ■ ⑤ JSONパース
// =========================
$data = json_decode($rawBody, true);
if (!is_array($data)) {
http_response_code(400);
echo "Invalid JSON";
exit;
}
// =========================
// ■ ⑥ データ処理(例)
// =========================
foreach ($data as $item) {
$goodsId = $item['goods_id'] ?? null;
if (is_null($goodsId)) {
continue;
}
// TODO: 在庫更新処理など
}
// =========================
// ■ 正常終了
// =========================
http_response_code(200);
echo "OK";
※本仕様はHTTPおよびHMAC署名の一般的な仕様に基づいているため、他の言語でも同様に実装可能です。
