Webhooks API

Webhook을 사용하면 Mercozy 스토어에서 이벤트가 발생할 때 실시간 HTTP 알림을 받을 수 있습니다. API를 폴링하는 대신 URL을 등록하면 Mercozy가 자동으로 이벤트 데이터를 POST합니다.

빠른 시작

3단계로 시작하세요:

1단계: 엔드포인트 등록

API 키를 가져오세요 설정 > 통합 > API 키. 관리자 권한이 필요합니다. 웹훅 서명 시크릿(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 엔드포인트 사용Mercozy는 프로덕션 환경에서 Webhook 데이터 보호를 위해 HTTPS URL을 요구합니다.

  • 로깅 및 모니터링모든 수신 Webhook을 기록하고 실패를 모니터링하세요. 전송 로그 API를 사용하여 전송 상태를 확인하세요.