الانتقال إلى المحتوى
iRoamly Shop

إشعارات Webhook

استخدم Webhooks لاستقبال نتائج تسليم رموز QR والتجديد في تطبيقك.

إشعارات Webhook

مقدمة

استخدم Webhooks لاستقبال نتائج تسليم رموز QR والتجديد في تطبيقك.

ما هو Webhook؟

يرسل iRoamly إشعارات Webhook بنتائج تسليم رموز QR والتجديد. يستخدم كل Webhook بروتوكول HTTPS ويتضمن حمولة JSON. استخدم Webhooks من أجل:

  • استقبال معلومات رمز QR بعد تحويل رمز استرداد أو إتمام شراء رمز QR مباشرةً.
  • استقبال نتائج التجديد عبر Webhook: esim.renewal.success عندما يصبح رمز QR للتجديد جاهزًا، وesim.renewal.failed عند فشل طلب التجديد لدى المزوّد.

إذا لم تستجب نقطة النهاية بحالة 2xx، يجري iRoamly ما يصل إلى 5 محاولات تسليم إجمالًا: الأولى فورًا، ثم إعادة المحاولة بعد 30 ثانية، ودقيقتين، و3 دقائق، و5 دقائق.

خطوات استقبال Webhook

يمكنك البدء في استقبال الأحداث في الوقت الفعلي في تطبيقك باتباع الخطوات التالية:

  • أنشئ نقطة نهاية محلية لاستقبال الطلبات
  • سجّل نقطة نهاية Webhook ضمن المطوّرون > إشعارات Webhook في لوحة تحكم iRoamly Shop

1. أنشئ نقطة نهاية محلية لاستقبال الطلبات

في تطبيقك المحلي، أنشئ مسارًا جديدًا يمكنه قبول طلبات POST.

على سبيل المثال، يمكنك إضافة مسار API في Next.js:

typescript
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.

يمكنك إنشاء نفق إلى خادم localhost باستخدام أداة مثل ngrok.

صفحة إشعارات Webhook في لوحة التحكم مع فتح لوحة «Webhook جديد»: حقل عنوان URL لـ Webhook وحالة مفعّل / معطّل

3. اختبر أن نقطة نهاية Webhook تعمل بشكل صحيح

حوّل رمز استرداد تجريبيًا إلى رمز QR، أو اشترِ رمز QR مباشرةً، للتحقق من أن نقطة نهاية Webhook تستقبل الحدث.

إشعارات Webhook

أنواع الأحداث

قائمة بأنواع الأحداث المدعومة وحمولاتها.

نوع الحدثوقت الإرسالملاحظات
esim.qrcodeتم تحويل رمز استرداد إلى رمز QR، أو اكتمل شراء رمز QR مباشرةً.دون تغيير. قيمة isrenew دائمًا 0.
esim.renewal.successنجح التجديد وأصبح رمز QR لرمز التجديد جاهزًا.جديد. لم تعد عمليات التجديد ترسل esim.qrcode.
esim.renewal.failedفشل التجديد لتعذّر تقديم الطلب لدى المزوّد.جديد. يُرسل فقط عند فشل الطلب لدى المزوّد.

التسليم

يُسلَّم كل حدث بالطريقة نفسها: طلب POST بنص JSON إلى كل نقطة نهاية مشتركة في الحدث. تُعد أي استجابة 2xx تسليمًا ناجحًا؛ وإلا تُعاد المحاولة، بما يصل إلى 5 محاولات إجمالًا (الأولى فورًا، ثم إعادة المحاولة بعد 30 ثانية، ودقيقتين، و3 دقائق، و5 دقائق). يحمل كل طلب الترويسات التالية:

الترويسةالوصفالنوع
X-Webhook-Eventنوع الحدث: esim.qrcode أو esim.renewal.success أو esim.renewal.failed.String
X-Webhook-Deliveryمعرّف التسليم.String
X-Webhook-Timestampوقت توقيع الطلب، بثواني Unix.String
X-Webhook-Signaturesha256= متبوعة بقيمة HMAC-SHA256 الست عشرية لنص الطلب الخام.String
X-Webhook-Signature-V2v1= متبوعة بقيمة HMAC-SHA256 الست عشرية لـ "{timestamp}.{body}". أثناء تدوير السر، تحمل عدة قيم v1= مفصولة بفواصل.String

راجع التحقق من طلبات Webhook لمعرفة كيفية التحقق من التوقيعات.

esim.qrcode

المعلومات المتعلقة برمز QR لـ eSIM التي تُرجع بعد استرداد رمز QR لـ eSIM أو شرائه.

نموذج لنص الطلب

json
{
	"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"
	}
إشعارات Webhook

esim.renewal.success

يُرسَل عند نجاح التجديد: بعد أن يُرجع المزوّد تفاصيل التنزيل لطلب التجديد، يُنشئ النظام رمز QR لرمز التجديد، وتصبح قيمة status الخاصة به 2 (تم الاسترداد).

ترويسات الطلب

X-Webhook-Event:esim.renewal.success

يحمل الطلب أيضًا X-Webhook-Delivery وX-Webhook-Timestamp وX-Webhook-Signature وX-Webhook-Signature-V2، كما هو الحال في كل حدث (راجع أنواع الأحداث).

نموذج لنص الطلب

json
{
	"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"
}

الحقول

الحقلالوصفالنوع
codeدائمًا 0.Int
event_typeesim.renewal.successString
data.codeرمز الاسترداد الجديد المُنشأ لهذا التجديد. استخدمه مع Query QR Code (qrcodeQuery)، أو للتجديد مرة أخرى.String
data.renewal_father_codeرمز الاسترداد الأصلي (الأب) الذي تم تجديده.String
data.renew_order_idمعرّف طلب التجديد لدى المزوّد.String
data.plan_nameاسم باقة التجديد.String
data.qrcodeعنوان URL لصورة رمز QR.String
data.qrcode_contentسلسلة LPA؛ يمكن استيرادها مباشرة.String
data.sm_dp_addressعنوان SM-DP+.String
data.activation_codeرمز التفعيل.String
data.iccidICCID. قد يكون فارغًا.String
data.download_urlسلسلة التنزيل التي يُرجعها المزوّد.String
data.create_atوقت الإنشاء: وقت الخادم، بتنسيق YYYY-MM-DD HH:mm:ss.String
data.isrenewدائمًا 1.Int
data.iscouldrenewalما إذا كان يمكن تجديد رمز الاسترداد الجديد مرة أخرى: 1 - يمكن تجديده 2 - لا يمكن تجديده 3 - منتهي الصلاحيةInt
إشعارات Webhook

esim.renewal.failed

يُرسل عند فشل التجديد: عندما يردّ المزوّد على طلب التجديد برمز غير 0000، أو عند فشل الطلب المرسل إلى المزوّد.

(ملاحظة: لا يؤدي غياب الاستدعاء من المزوّد أو تأخره إلى إطلاق هذا الحدث. اضبط مهلة زمنية وارجع إلى الاستعلام عن الرمز — راجع التعامل مع أحداث التجديد.)

ترويسات الطلب

X-Webhook-Event:esim.renewal.failed

يحمل الطلب أيضًا X-Webhook-Delivery وX-Webhook-Timestamp وX-Webhook-Signature وX-Webhook-Signature-V2، كما هو الحال في كل حدث (راجع أنواع الأحداث).

نموذج لنص الطلب

json
{
	"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"
}

الحقول

الحقلالوصفالنوع
codeدائمًا -1.Int
event_typeesim.renewal.failedString
data.codeرمز التجديد المُنشأ لهذه المحاولة. لم يُجهَّز وليس له رمز QR.String
data.renewal_father_codeرمز الاسترداد الأصلي (الأب) الذي كان مقررًا تجديده.String
data.plan_nameاسم باقة التجديد.String
data.error_msgالخطأ الذي أرجعه المزوّد، لاستكشاف الأخطاء وإصلاحها.String
data.create_atوقت الإنشاء: وقت الخادم، بتنسيق YYYY-MM-DD HH:mm:ss.String
data.isrenewدائمًا 1.Int
إشعارات Webhook

عمليات التجديد و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.
إشعارات Webhook

الاشتراك في الأحداث

تُشترك نقاط النهاية الجديدة في الأحداث الثلاثة جميعها افتراضيًا. وتستقبل نقاط النهاية الحالية esim.renewal.success وesim.renewal.failed تلقائيًا — دون الحاجة إلى أي تغيير.

إشعارات Webhook

التعامل مع أحداث التجديد

  • اجعل المعالج متساوي القوة (idempotent). قد تؤدي إعادة المحاولة إلى تسليم الحدث نفسه أكثر من مرة، لذا أزل التكرار حسب X-Webhook-Delivery أو حسب event_type + data.code، وتجاهل الأحداث التي عالجتها بالفعل.
  • استخدم آلية احتياطية بمهلة زمنية. إذا لم يصل esim.renewal.success ولا esim.renewal.failed خلال وقت معقول، فاستعلم عن الرمز باستخدام واجهة الاستعلام (مثل Query QR Code) بدلًا من افتراض فشل التجديد.
  • لا تعتمد على esim.renewal.failed لتقرير عمليات الاسترداد. فهو يُبلغ فقط بفشل الطلب لدى المزوّد؛ أما إعادة الرصيد وتوقيتها فيُقرَّران بشكل منفصل، لذا لا تُعِد المبالغ إلى عملائك بناءً على هذا الحدث.
إشعارات Webhook

التحقق من طلبات Webhook

تحقّق من توقيع iRoamly على طلبات Webhook.

كيف تتحقق من توقيع iRoamly؟

يُرسل توقيع iRoamly في ترويسة X-Webhook-Signature لطلب Webhook، على شكل sha256= متبوعة بالتوقيع المرمّز بالنظام الست عشري. يُنشأ التوقيع باستخدام خوارزمية HMAC-SHA256 مع سر Webhook كمفتاح، ونص الطلب الخام (كما استُلم تمامًا، قبل أي تحليل لـ JSON) كرسالة.

نموذج لترويسة Webhook

json
{
'X-Webhook-Signature': 'sha256=dd7bdd2cf1f6bac6e171c6c508c157b7cd3cc1fd196394277fb59ba0bdd9b87b'
}

يمكنك العثور على سر Webhook ضمن المطوّرون > إشعارات Webhook في لوحة التحكم.

صفحة إشعارات Webhook في لوحة التحكم: نقطة نهاية Webhook مع عنوان URL وسر التوقيع (كشف)، وسجل التسليم

لإنشاء التوقيع، يمكنك استخدام مقتطف التعليمات البرمجية التالي:

typescript
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= متبوعة بقيمة HMAC-SHA256 المرمّزة بالنظام الست عشري، باستخدام سر Webhook نفسه، لـ {timestamp}.{body} — أي قيمة ترويسة X-Webhook-Timestamp، ثم نقطة، ثم نص الطلب الخام.

بعد تدوير سر Webhook، يظل السر القديم صالحًا لمدة 24 ساعة. خلال تلك الفترة، يظل X-Webhook-Signature موقّعًا بالسر القديم، ويحمل X-Webhook-Signature-V2 قيمة واحدة لكل سر، مفصولة بفواصل (v1=<old>,v1=<new>): اقبل الطلب إذا تطابقت أي قيمة.