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 回配信を試みます: 1 回目は即時、その後 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 回試行します(1 回目は即時、その後 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に含まれます。
イベントの購読
新しいエンドポイントは、デフォルトで 3 つのイベントすべてを購読します。既存のエンドポイントも esim.renewal.success と esim.renewal.failed を自動的に受信します。変更は不要です。
更新イベントの処理
- ハンドラーは冪等にしてください。再試行により同じイベントが複数回配信される場合があるため、
X-Webhook-Deliveryまたはevent_type+data.codeで重複を排除し、処理済みのイベントは無視してください。 - タイムアウト時のフォールバックを用意してください。妥当な時間内に
esim.renewal.successもesim.renewal.failedも届かない場合は、更新が失敗したとみなさず、照会 API(Query QR Code など)でコードを照会してください。 esim.renewal.failedを返金の判断に使用しないでください。このイベントは上流の注文が失敗したことのみを通知します。クレジットを返金するかどうか、またその時期は別途決定されるため、このイベントに基づいてお客様に返金しないでください。
Webhook リクエストの検証
Webhook リクエストの iRoamly 署名を検証します。
iRoamly 署名を検証するには?
iRoamly 署名は、Webhook リクエストの X-Webhook-Signature ヘッダーで、sha256= に続く 16 進エンコードされた署名として送信されます。署名は HMAC-SHA256 アルゴリズムで生成され、キーには Webhook シークレット、メッセージには生のリクエストボディ(JSON を解析する前の、受信したそのままの状態)を使用します。
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 にはシークレットごとに 1 つずつ、カンマ区切りで値が含まれます(v1=<old>,v1=<new>): いずれかの値が一致すればリクエストを受け入れてください。