Tổng Kho eSIM
발신 웹훅 · 이벤트 8개

웹훅

POST /v1/webhooks로 URL을 등록하고 PUT /v1/webhooks/{id}로 수정합니다. 생성 시 CHECK_HEALTH에 2xx가 필요합니다. API 키와 다른 전용 비밀 키로 이벤트를 서명합니다.

최종 기준은 REST입니다. 웹훅을 놓쳐도 GET /v1/orders?updated_since=…로 상태를 복구할 수 있도록 대사를 설계하세요.

webhook-events.ko.json

이벤트 목록

event_type발생 시점주요 데이터 필드
order.completed주문 확정 및 eSIM 준비 완료
order_idexternal_refitems[] (order_item_id, iccid)
order.failed주문 미완료(발급 실패 등)
order_idexternal_refreason
esim.deliveredeSIM이 발급되고 설치 데이터가 준비됨

`order_id`와 `external_ref`로 연결합니다. `lpa`는 POST 직전에 복호화하며 전송 기록에 평문으로 저장하지 않습니다. QR 이미지 URL은 없으므로 `lpa`로 생성하거나 `GET /v1/esims/{id}`에서 `qr_code_base64`를 조회하세요.

order_item_idorder_idexternal_reficcidlpa
esim.activatedeSIM 설치 및 활성화(smdp enabled/in_use)

`order_id`와 구매 시 보낸 `external_ref`로 eSIM을 주문과 연결하세요。

order_item_idorder_idexternal_reficcidactivated_at
esim.usage_threshold사용량 75% / 90% 기준 도달

`order_id`와 `external_ref`로 주문에 연결합니다. 새로 넘은 기준 중 가장 높은 값만 발송합니다(0→95%는 90만). `threshold`는 최소 이 기준을 넘었다는 뜻입니다.

order_item_idorder_idexternal_refthreshold (75/90)used_bytesdata_bytes
esim.expiring만료 3일 / 1일 전

`order_id`와 구매 시 보낸 `external_ref`로 eSIM을 주문과 연결하세요。

order_item_idorder_idexternal_refdays_remaining (3/1)expires_at
wallet.low_balance지갑 25% / 10% 경고 기준 도달

`threshold`는 백분율(25/10)이며 실제 비율이 있을 때만 포함합니다. 없으면 필드를 생략하므로 `balance`를 직접 비교하세요. `threshold`에 VND 금액을 보내지 않습니다.

threshold (25/10)balancecurrency
catalog.updated카탈로그 변경: 패키지 추가·수정·숨김, 기본 가격 변경 또는 품절

조직마다 가격이 달라 가격은 포함하지 않습니다. `GET /v1/catalog/packages`로 조직 가격을 조회하세요. 짧은 구간(기본 10분)의 변경을 하나의 `changes[]` 웹훅으로 묶고 패키지당 한 항목만 남깁니다. 수백 개를 동기화해도 수백 웹훅이 발송되지 않습니다. 테스트와 실제 모두 적용합니다.

changes[] (package_code, change: price|availability|package, occurred_at)change_count
json
{
  "event_id": "018f3c00-0000-7000-8000-0000000000c1",
  "event_type": "ping",
  "occurred_at": "2026-07-11T07:29:00Z",
  "is_testmode": true,
  "data": {
    "message": "TongKho eSIM webhook health check"
  }
}

응답 형식 및 서명 헤더

모든 웹훅은 같은 봉투를 사용합니다. `HMAC-SHA256(webhook_secret, timestamp\nraw_body)`를 소문자 hex로 `X-TKE-Webhook-Signature`에 서명합니다. 24시간 교체 구간에는 `X-TKE-Webhook-Signature-Old`도 보냅니다. 최소 1회 전송이므로 `event_id`로 중복 제거하세요.

json
{
  "event_id": "018f3c00-0000-7000-8000-0000000000b0",
  "event_type": "order.completed",
  "occurred_at": "2026-07-11T07:30:00Z",
  "is_testmode": false,
  "data": {
    "order_id": "018f2b00-0000-7000-8000-00000000009a",
    "external_ref": "partner-cart-9931",
    "items": [
      {
        "order_item_id": "018f2b00-0000-7000-8000-000000000001",
        "iccid": "8984012345678901234"
      }
    ]
  }
}
필드설명
data이벤트 유형별 데이터입니다(아래 참고).
event_id이벤트별로 고유하고 고정된 UUID입니다(중복 제거).
event_type이벤트 유형입니다.
is_testmode테스트 키에서 발생했으면 true입니다。
occurred_atISO-8601 UTC.

카탈로그 동기화: catalog.updated

요금제 추가·수정·숨김·기본가·재고 변경 시 발생하며 변경 사항을 다음 배열로 모읍니다: changes[] 배열에 수백 개 변경이 있어도 단 한 번 의 전송만 각 엔드포인트에 보냅니다.

json
{
  "event_id": "018f3c00-0000-7000-8000-0000000000c1",
  "event_type": "catalog.updated",
  "occurred_at": "2026-07-11T08:10:00Z",
  "is_testmode": false,
  "data": {
    "changes": [
      {
        "package_code": "THAY-BANG-MA-GOI-CUA-BAN",
        "change": "price",
        "occurred_at": "2026-07-11T08:02:11Z"
      },
      {
        "package_code": "VN_10GB_30D",
        "change": "availability",
        "occurred_at": "2026-07-11T08:04:52Z"
      },
      {
        "package_code": "JP_3GB_7D",
        "change": "package",
        "occurred_at": "2026-07-11T08:09:30Z"
      }
    ],
    "change_count": 3
  }
}
가격이 없는 것은 의도된 설계

판매가는 조직별로 다릅니다 . 공통 가격은 부정확하고 정보를 노출합니다. 이 이벤트는 동기화 신호입니다 : 다음 호출로 GET /v1/catalog/packages?market=… 가격을 갱신하세요.

change 허용 값 3개: price (기본가 변경), availability (재고 있음/없음), package (신규/수정/숨김). 알 수 없는 값도 동기화를 시작하세요.

서명, 재시도 및 중복 제거 기준 event_id 는 일반 이벤트와 같습니다. 테스트와 운영은 다음 단위로 분리합니다: is_testmode.

웹훅 서명 검증

X-TKE-Signature는 webhook_secret과 본문 원본 바이트로 계산한 HMAC-SHA256입니다.

text
signing_string = timestamp + "\n" + raw_body   # timestamp = header X-TKE-Webhook-Timestamp
signature      = HMAC_SHA256(webhook_secret, signing_string)   → hex lowercase

# 재전송 공격 방지를 위해 ±300초 확인.
# 수신 바이트 그대로 서명하고 JSON을 다시 직렬화하지 마세요.

재시도 정책

1 phút→5 phút→30 phút→2 giờ→6 giờ

2xx 외 응답 또는 5초 초과 시 24 giờ 동안 지수 간격으로 재시도합니다: 1 phút → 5 phút → 30 phút → 2 giờ → 6 giờ.

웹훅 핵심 지침 4가지

1. 비동기 처리 및 즉시 200 응답
본문을 큐에 넣고 1초 내 200을 반환하세요. 무거운 동기 작업은 피하세요. 제한 시간은 5초입니다.
2. 멱등성 및 중복 제거
최소 1회 전달하므로 event_id 또는 data.order_id / data.order_item_id로 중복을 제거하세요.
3. 운영과 테스트 수신 주소 분리
키마다 웹훅 설정이 독립적입니다. 테스트 데이터가 운영 DB에 섞이지 않도록 URL을 분리하세요.
4. 정기 REST 대사
장기 네트워크 장애로 이벤트가 누락될 수 있습니다. GET /v1/orders?updated_since=…를 주기적으로 조회하세요.

필드 동작 참고

esim.delivered.lpa 는 POST 직전에 복호화되며 평문 저장하지 않습니다. LPA 또는 GET /v1/esims/{id}로 QR을 만드세요.

esim.usage_threshold: 는 새로 넘은 가장 높은 임계값만 전송합니다(0→95%는 threshold=90).

wallet.low_balance.threshold 는 백분율(25/10)이며 VND 금액이 아닙니다.

catalog.updated 는 가격·세부 재고 없이 요금제 코드와 변경 유형만 포함합니다.