Webhooks API

Webhook を使用すると、Mercozy ストアでイベントが発生した際にリアルタイムで HTTP 通知を受け取れます。API をポーリングする代わりに、URL を登録すれば Mercozy が自動的にイベントデータを POST します。

クイックスタート

3 ステップで始められます:

ステップ 1:エンドポイントを登録

API キーを取得してください 設定 > 連携 > API キー. 管理者権限が必要です。Webhook 署名シークレット(whsec_xxx)はエンドポイント作成時に自動生成され、一度のみ表示されます。

bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks" \
  -H "X-API-Key: mk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "My ERP Integration",
    "url": "https://your-app.com/webhooks/mercozy",
    "events": ["order.created", "order.cancelled", "payment.received"]
  }'
ステップ 2:イベントを処理
javascript
app.post('/webhooks/mercozy', (req, res) => {
  // 1. Verify signature (see below)
  const signature = req.headers['x-webhook-signature'];
  if (!verifySignature(req.body, signature, WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }

  // 2. Process the event
  const { type, data } = req.body;
  switch (type) {
    case 'order.created':
      syncOrderToERP(data);
      break;
    case 'payment.received':
      updateAccountingSystem(data);
      break;
  }

  // 3. Respond quickly with 200
  res.status(200).json({ received: true });
});
ステップ 3:エンドポイントをテスト
bash
curl -X POST "https://api.mercozy.com/api/v1/external/webhooks/{id}/test" \
  -H "X-API-Key: mk_live_your_key_here"

エンドポイント

GET

/webhooks

webhooks:read

登録済みのすべてのWebhookエンドポイントを一覧表示します。

POST

/webhooks

webhooks:write

イベント通知を受信するための新しいWebhookエンドポイントを登録します。

PUT

/webhooks/:id

webhooks:write

既存のWebhookエンドポイントを更新します(URL、イベント、またはアクティブステータス)。

DELETE

/webhooks/:id

webhooks:write

Webhookエンドポイントを削除します。イベントは配信されなくなります。

フィールドリファレンス
フィールド必須説明

id

string

いいえ

一意のWebhook識別子(読み取り専用)

name

string

はい

エンドポイントの説明的な名前

url

string

はい

Webhookイベントを受信するHTTPSエンドポイントURL

events

string[]

はい

購読するイベントタイプの配列

secret

string

いいえ

ペイロード検証用の署名シークレット(読み取り専用、作成時に生成)

isActive

boolean

いいえ

Webhookがアクティブかどうか(デフォルト:true)

createdAt

datetime

いいえ

ISO 8601タイムスタンプ(読み取り専用)


利用可能なイベントタイプ

Mercozy は 6 カテゴリ、18 種類の Webhook イベントに対応しています。必要なイベントのみ購読してください。

注文
  • order.created

    新しい注文が作成された時に発火

  • order.updated

    注文内容が変更された時に発火

  • order.cancelled

    注文がキャンセルされた時に発火

  • order.completed

    注文が完了した時に発火

  • order.status_changed

    注文ステータスが変更された時に発火

決済
  • payment.received

    決済が完了または代引き回収時に発火

  • payment.refunded

    返金または決済キャンセル時に発火

商品
  • product.created

    新しい商品が追加された時に発火

  • product.updated

    商品情報が変更された時に発火

  • product.deleted

    商品が削除された時に発火

在庫
  • stock.low

    在庫がしきい値を下回った時に発火

  • stock.updated

    在庫数が変更された時に発火

顧客
  • customer.created

    新しい顧客が登録された時に発火

  • customer.updated

    顧客情報が更新された時に発火

配送
  • delivery.batch_started

    配送バッチが出発した時に発火

  • delivery.batch_completed

    バッチ内の全配送が完了した時に発火

  • delivery.completed

    個別の配送が完了した時に発火

  • delivery.failed

    配送の試行が失敗した時に発火


Webhookペイロード

各Webhook配信にはイベントタイプ、タイムスタンプ、関連するリソースデータが含まれます。

注文イベントペイロード
json
{
  "id": "evt_clx1abc2def3",
  "type": "order.created",
  "timestamp": "2026-03-19T10:30:00Z",
  "data": {
    "id": "clx9order123",
    "orderNumber": "ORD-1042",
    "status": "PENDING",
    "total": 4999,
    "currency": "USD"
  }
}
決済イベントペイロード
json
{
  "id": "evt_clx2pay4ghi5",
  "type": "payment.received",
  "timestamp": "2026-03-19T10:35:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042",
    "amount": 4999,
    "currency": "USD",
    "paymentMethod": "CARD",
    "status": "CAPTURED"
  }
}
商品イベントペイロード
json
{
  "id": "evt_clx3prod6jkl",
  "type": "product.created",
  "timestamp": "2026-03-19T11:00:00Z",
  "data": {
    "id": "clx9prod789",
    "name": "Organic Coffee Beans",
    "sku": "COF-001",
    "price": 1299,
    "status": "ACTIVE"
  }
}
配送イベントペイロード
json
{
  "id": "evt_clx4del7mno",
  "type": "delivery.completed",
  "timestamp": "2026-03-19T14:22:00Z",
  "data": {
    "orderId": "clx9order123",
    "orderNumber": "ORD-1042"
  }
}

HTTP ヘッダー

すべての Webhook リクエストには以下のヘッダーが含まれます:

フィールド必須説明

Content-Type

string

はい

application/json

X-Webhook-Signature

string

はい

HMAC-SHA256 署名:sha256={16進数ダイジェスト}

X-Webhook-Timestamp

string

はい

Unix ミリ秒タイムスタンプ

X-Webhook-ID

string

はい

重複排除用のユニークなイベント ID

User-Agent

string

はい

Mercozy-Webhook/1.0 (+https://www.mercozy.com/docs/webhooks)


署名検証

すべての Webhook には HMAC-SHA256 署名を含む X-Webhook-Signature ヘッダーが付与されます。イベント処理前に必ずこの署名を検証し、リクエストが Mercozy からのものであることを確認してください。

Node.js
javascript
const crypto = require('crypto');

function verifyWebhook(rawBody, signature, timestamp, secret) {
  // Signature is computed over "timestamp.body"
  const message = timestamp + '.' + rawBody;
  const expected = 'sha256=' + crypto
    .createHmac('sha256', secret)
    .update(message)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// Express middleware
app.post('/webhooks', express.raw({ type: 'application/json' }), (req, res) => {
  const sig = req.headers['x-webhook-signature'];
  const ts = req.headers['x-webhook-timestamp'];
  if (!verifyWebhook(req.body, sig, ts, process.env.WEBHOOK_SECRET)) {
    return res.status(401).send('Invalid signature');
  }
  const event = JSON.parse(req.body);
  // Process event...
  res.status(200).json({ received: true });
});
Python
python
import hmac
import hashlib

def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
    # Signature is computed over "timestamp.body"
    message = (timestamp + '.').encode() + payload
    expected = 'sha256=' + hmac.new(
        secret.encode(),
        message,
        hashlib.sha256
    ).hexdigest()
    return hmac.compare_digest(signature, expected)

# Flask example
@app.route('/webhooks', methods=['POST'])
def handle_webhook():
    sig = request.headers.get('X-Webhook-Signature')
    ts = request.headers.get('X-Webhook-Timestamp')
    if not verify_webhook(request.data, sig, ts, WEBHOOK_SECRET):
        return 'Invalid signature', 401
    event = request.get_json()
    # Process event...
    return {'received': True}, 200
PHP
php
<?php
function verifyWebhook(string $payload, string $signature, string $timestamp, string $secret): bool {
    // Signature is computed over "timestamp.body"
    $message = $timestamp . '.' . $payload;
    $expected = 'sha256=' . hash_hmac('sha256', $message, $secret);
    return hash_equals($expected, $signature);
}

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_WEBHOOK_TIMESTAMP'] ?? '';
if (!verifyWebhook($payload, $signature, $timestamp, $webhookSecret)) {
    http_response_code(401);
    exit('Invalid signature');
}
$event = json_decode($payload, true);
// Process event...
http_response_code(200);
echo json_encode(['received' => true]);

リトライポリシー

エンドポイントが 2xx 以外のステータスを返すかタイムアウト(10 秒)した場合、Mercozy は指数バックオフで再試行します:

フィールド必須説明

試行 1

いいえ

即時

試行 2

いいえ

遅延 ~1s

試行 3

いいえ

遅延 ~4s

3 回の再試行が失敗すると、配信は失敗としてマークされます。ダッシュボードまたは API から手動で再試行できます。


ベストプラクティス

  • 5 秒以内に応答200 ステータスを即座に返し、イベントは非同期で処理してください。Mercozy のタイムアウトは 10 秒です。

  • 署名を常に検証イベント処理前に X-Webhook-Signature ヘッダーを確認し、なりすましリクエストを防いでください。

  • 重複処理(冪等性)X-Webhook-ID ヘッダーで重複を排除してください。処理済みのイベント ID を保存し、既に処理したものはスキップしてください。

  • HTTPS エンドポイントを使用本番環境では Webhook データの安全な転送のため HTTPS URL が必須です。

  • ログ記録と監視すべての受信 Webhook をログに記録し、失敗を監視してください。配信ログ API で配信状況を確認できます。