Webhook 알림
Webhook을 사용하여 QR 코드 전송 및 갱신 결과를 애플리케이션에서 받으세요.
소개
Webhook을 사용하여 QR 코드 전송 및 갱신 결과를 애플리케이션에서 받으세요.
Webhook이란?
iRoamly는 QR 코드 전송 및 갱신 결과에 대한 Webhook 알림을 보냅니다. 각 Webhook은 HTTPS를 사용하며 JSON 페이로드를 포함합니다. Webhook으로 다음 작업을 할 수 있습니다:
- 교환 코드가 QR 코드로 전환되거나 QR 코드 직접 구매가 완료된 후 QR 코드 정보를 수신합니다.
- Webhook으로 갱신 결과를 수신합니다: 갱신 QR 코드가 준비되면
esim.renewal.success, 업스트림 갱신 주문이 실패하면esim.renewal.failed.
엔드포인트가 2xx 상태로 응답하지 않으면 iRoamly는 총 최대 5회 전송을 시도합니다: 첫 번째는 즉시, 이후 30초, 2분, 3분, 5분 후에 재시도합니다.
Webhook 수신 단계
다음 단계에 따라 앱에서 실시간 이벤트 수신을 시작할 수 있습니다:
- 요청을 받을 로컬 엔드포인트 만들기
- iRoamly Shop 대시보드의 개발자 > Webhook 알림에서 Webhook 엔드포인트 등록하기
1. 요청을 받을 로컬 엔드포인트 만들기
로컬 애플리케이션에서 POST 요청을 받을 수 있는 새 라우트를 만드세요.
예를 들어 Next.js에 API 라우트를 추가할 수 있습니다:
import type { NextApiRequest, NextApiResponse } from 'next';
export default (req: NextApiRequest, res: NextApiResponse) => {
if (req.method === 'POST') {
const payload = req.body;
console.log(payload);
res.status(200);
}
};이벤트를 받으면 HTTP 200 OK로 응답하여 이벤트가 성공적으로 전달되었음을 iRoamly에 알려야 합니다.
2. 개발용 Webhook 엔드포인트 등록하기
공개적으로 접근 가능한 HTTPS URL을 iRoamly Shop 대시보드에 등록하세요.
ngrok 같은 도구로 localhost 서버에 터널을 만들 수 있습니다.

3. Webhook 엔드포인트가 제대로 작동하는지 테스트하기
테스트 교환 코드를 QR 코드로 전환하거나 QR 코드를 직접 구매하여 Webhook 엔드포인트가 이벤트를 수신하는지 확인하세요.
이벤트 유형
지원되는 이벤트 유형 및 페이로드 목록입니다.
전송
모든 이벤트는 동일한 방식으로 전송됩니다: 이벤트를 구독한 각 엔드포인트로 JSON 본문을 담은 POST 요청을 보냅니다. 2xx 응답은 모두 전송 완료로 간주되며, 그렇지 않으면 재시도하여 총 최대 5회 시도합니다(첫 번째는 즉시, 이후 30초, 2분, 3분, 5분 후 재시도). 각 요청에는 다음 헤더가 포함됩니다:
서명 확인 방법은 Webhook 요청 검증을 참조하세요.
esim.qrcode
eSIM QR 코드를 교환하거나 구매한 후 반환되는 eSIM QR 코드 관련 정보입니다.
샘플 요청 본문
{
"code": 0,
"data": {
"activation_code": "CD112885573C49DDA42F64C905B925F4",
"code": "UtTpoKCe769u2tt",
"create_at": "2025-09-01 11:34:30",
"isrenew": 0,
"order_id": "ESIM202509021134343282",
"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
"qrcode": "https://www.iroamly.com/qrcode/20250901/xSQfryvOWo0QUhsGcbpeTm9wWYfGu9BQ.png",
"qrcode_content": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
"sm_dp_address": "rsp1.cmlink.com"
},
"event_type": "esim.qrcode"
}esim.renewal.success
갱신에 성공하면 전송됩니다: 업스트림 공급자가 갱신 주문의 다운로드 정보를 반환하면 갱신 코드의 QR 코드가 생성되고 status가 2(교환됨)로 바뀝니다.
요청 헤더
esim.renewal.success모든 이벤트와 마찬가지로 요청에는 X-Webhook-Delivery, X-Webhook-Timestamp, X-Webhook-Signature, X-Webhook-Signature-V2도 포함됩니다(이벤트 유형 참조).
샘플 요청 본문
{
"code": 0,
"data": {
"activation_code": "CD112885573C49DDA42F64C905B925F4",
"code": "RnB7xTq2Lm9pQaZ",
"create_at": "2026-10-28 09:12:41",
"download_url": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
"iccid": "8944501234567890123",
"iscouldrenewal": 1,
"isrenew": 1,
"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
"qrcode": "https://www.iroamly.com/qrcode/20261028/xSQfryvOWo0QUhsGcbpeTm9wWYfGu9BQ.png",
"qrcode_content": "LPA:1$rsp1.cmlink.com$CD352885573C49DDA42F64C905B925F4",
"renew_order_id": "TG202610280912410001",
"renewal_father_code": "UtTpoKCe769u2tt",
"sm_dp_address": "rsp1.cmlink.com"
},
"event_type": "esim.renewal.success"
}필드
esim.renewal.failed
갱신에 실패하면 전송됩니다: 업스트림 공급자가 갱신 주문에 0000 이외의 코드로 응답하거나 공급자에 대한 요청이 실패한 경우입니다.
(참고: 업스트림 공급자의 콜백이 없거나 늦어지는 경우에는 이 이벤트가 발생하지 않습니다. 타임아웃을 설정하고 코드 조회로 대체하세요. 갱신 이벤트 처리를 참조하세요.)
요청 헤더
esim.renewal.failed모든 이벤트와 마찬가지로 요청에는 X-Webhook-Delivery, X-Webhook-Timestamp, X-Webhook-Signature, X-Webhook-Signature-V2도 포함됩니다(이벤트 유형 참조).
샘플 요청 본문
{
"code": -1,
"data": {
"code": "RnB7xTq2Lm9pQaZ",
"create_at": "2026-10-28 09:12:41",
"error_msg": "TuGe_RenewOrderEx RespCode: 9999",
"isrenew": 1,
"plan_name": "Japan-eSIM-3GB-15 Days-Daily",
"renewal_father_code": "UtTpoKCe769u2tt"
},
"event_type": "esim.renewal.failed"
}필드
갱신과 esim.qrcode
갱신은 더 이상 esim.qrcode로 전송되지 않습니다. 이 이벤트는 QR 코드 전환 및 QR 코드 직접 구매 시 전송됩니다. esim.qrcode 페이로드와 비교하면 다음과 같습니다:
event_type과X-Webhook-Event헤더는esim.renewal.success또는esim.renewal.failed이며,isrenew는1입니다.data.code는 갱신으로 생성된 새 교환 코드이며, 갱신된 코드는data.renewal_father_code입니다.esim.renewal.success에는renew_order_id,renewal_father_code,iscouldrenewal,download_url,iccid가 추가되며order_id는 없습니다.- 갱신 실패는
esim.renewal.failed로 알리며, 최상위code는-1이고 업스트림 오류는data.error_msg에 담깁니다.
이벤트 구독
새 엔드포인트는 기본적으로 세 가지 이벤트를 모두 구독합니다. 기존 엔드포인트는 esim.renewal.success와 esim.renewal.failed를 자동으로 수신하므로 변경할 필요가 없습니다.
갱신 이벤트 처리
- 핸들러를 멱등적으로 만드세요. 재시도로 같은 이벤트가 여러 번 전송될 수 있으므로
X-Webhook-Delivery또는event_type+data.code로 중복을 제거하고 이미 처리한 이벤트는 무시하세요. - 타임아웃 대체 처리를 사용하세요. 적절한 시간 내에
esim.renewal.success와esim.renewal.failed모두 도착하지 않으면 갱신이 실패했다고 가정하지 말고 조회 API(예: QR 코드 조회)로 코드를 조회하세요. - 환불 여부를
esim.renewal.failed로 판단하지 마세요. 이 이벤트는 업스트림 주문이 실패했다는 사실만 알립니다. 크레딧 환불 여부와 시기는 별도로 결정되므로 이 이벤트를 근거로 고객에게 환불하지 마세요.
Webhook 요청 검증
Webhook 요청의 iRoamly 서명을 검증합니다.
iRoamly 서명은 어떻게 검증하나요?
iRoamly 서명은 Webhook 요청의 X-Webhook-Signature 헤더에 sha256= 뒤에 16진수로 인코딩된 서명을 붙인 형태로 전송됩니다. 서명은 Webhook 시크릿을 키로, 원본 요청 본문(JSON 파싱 전, 받은 그대로)을 메시지로 하여 HMAC-SHA256 알고리즘으로 생성됩니다.
샘플 Webhook 헤더
{
'X-Webhook-Signature': 'sha256=dd7bdd2cf1f6bac6e171c6c508c157b7cd3cc1fd196394277fb59ba0bdd9b87b'
}Webhook 시크릿은 대시보드의 개발자 > Webhook 알림에서 확인할 수 있습니다.

서명을 생성하려면 다음 코드 스니펫을 사용할 수 있습니다:
import * as crypto from 'crypto';
generateSignature(payload: string, secret: string): string {
const computedSignature = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return 'sha256=' + computedSignature;
}위 코드 스니펫에서 payload는 원본 요청 본문이고 secret은 Webhook 시크릿입니다. 생성된 서명(sha256= 접두사 포함)을 X-Webhook-Signature 헤더 값과 비교하기만 하면 검증이 완료됩니다.
타임스탬프 서명(X-Webhook-Signature-V2)
각 요청에는 X-Webhook-Signature-V2도 포함됩니다: v1= 뒤에 동일한 Webhook 시크릿으로 {timestamp}.{body}(X-Webhook-Timestamp 헤더 값, 마침표, 원본 요청 본문)를 HMAC-SHA256으로 계산한 16진수 값이 붙습니다.
Webhook 시크릿을 교체한 후에도 이전 시크릿은 24시간 동안 유효합니다. 이 기간 동안 X-Webhook-Signature는 여전히 이전 시크릿으로 서명되며, X-Webhook-Signature-V2에는 시크릿별 값이 쉼표로 구분되어 포함됩니다(v1=<old>,v1=<new>). 하나라도 일치하면 요청을 수락하세요.