الـ Webhooks
استلم إشعارات HTTPS موقّعة عند تغيّر المدفوعات والاستردادات والإيداعات، مع إعادة محاولة تلقائية.
تُعلم الـ Webhooks خادمك بما يحدث في حسابك: نجاح عملية دفع، أو اكتمال استرداد، أو تحويل إيداع. وهي الطريقة الموثوقة لمعرفة نتيجة الدفع، لأنها تصل حتى لو أغلق العميل المتصفح قبل العودة إلى موقعك.
إعداد نقطة نهاية
نقطة النهاية (Endpoint) رابط على خادمك يستقبل طلبات POST. يجب أن تستخدم نقاط الوضع الحي https:// (الرابط الذي يبدأ بـ http:// يفشل بالخطأ 422 validation_error على url)، ويمكن لنقاط وضع الاختبار استخدام http:// أيضًا. ويجب أن يكون الرابط متاحًا من الإنترنت، إذ تُرفض العناوين في الشبكات الخاصة أو المحجوزة.
من لوحة التحكم: افتح المطورون ← Webhooks ← إضافة نقطة نهاية، وأدخل الرابط، واختر الأحداث واحفظ. انسخ سر التوقيع (whsec_…) الذي يظهر لك.
من الـ API:
curl https://api.teyra.co/v1/webhook-endpoints \
-H "Authorization: Bearer $TEYRA_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://shop.example.com/hooks/teyra",
"events": ["payment.succeeded", "payment.failed", "refund.succeeded"]
}'{
"id": "we_01JBX7C3HZ",
"object": "webhook_endpoint",
"url": "https://shop.example.com/hooks/teyra",
"events": ["payment.succeeded", "payment.failed", "refund.succeeded"],
"active": true,
"created_at": "2026-10-28T14:07:00.000Z",
"secret": "whsec_..."
}تُعاد قيمة secret في استجابة الإنشاء فقط. احفظها مع أسرارك الأخرى، فأنت تحتاجها للتحقق من التواقيع.
استخدم ["*"] لاستلام جميع أنواع الأحداث. اعرض نقاط النهاية عبر GET /v1/webhook-endpoints واحذف إحداها عبر DELETE /v1/webhook-endpoints/:id. نقاط نهاية وضع الاختبار منفصلة عن نقاط الوضع الحي: سجّل رابط الإنتاج بمفتاح حي.
أنواع الأحداث
| الحدث | متى يُرسل | data.object |
|---|---|---|
payment.succeeded | عند تحصيل الدفع. نفّذ الطلب. | Payment |
payment.failed | عند رفض الدفع أو حدوث خطأ. | Payment |
payment.canceled | عندما يلغي العميل الدفع من صفحة الدفع. | Payment |
payment.expired | عندما لا يُدفع قبل expires_at. | Payment |
refund.succeeded | عند اكتمال الاسترداد. | Refund |
refund.failed | عند فشل الاسترداد. | Refund |
deposit.paid | عند تحويل دفعة إلى حسابك البنكي. | Deposit |
محتوى الإشعار
كل Webhook طلب POST جسمه كائن Event بصيغة JSON:
{
"id": "evt_01JBX8A2NM",
"object": "event",
"type": "payment.succeeded",
"livemode": false,
"created_at": "2026-10-28T14:08:13.000Z",
"data": {
"object": {
"id": "pay_01JBX4T9W2",
"object": "payment",
"livemode": false,
"amount": 12500,
"currency": "KWD",
"amount_refunded": 0,
"status": "succeeded",
"reference": "1042",
"payment_method": "knet",
"metadata": { "order_id": "1042" },
"paid_at": "2026-10-28T14:08:12.000Z"
}
}
}قيمة data.object هي الكائن الكامل (مختصر هنا) كما كان لحظة وقوع الحدث.
الترويسات المرسلة مع كل طلب:
| الترويسة | القيمة |
|---|---|
Content-Type | application/json |
Teyra-Signature | t=1730124420,v1=5f2b…. راجع التحقق من التواقيع. |
Teyra-Event-Id | معرّف الحدث، وهو نفسه id في الجسم. استخدمه لتجاهل التكرار. |
User-Agent | TeyraPay-Webhooks/1.0 |
معالجة الحدث
- اقرأ جسم الطلب الخام.
- تحقّق من التوقيع، وارفض الطلب بالرمز
400إذا لم يتطابق. - إذا عالجت
Teyra-Event-Idهذا من قبل، أعِد200وتوقف. - أعِد رمزًا من فئة
2xxبسرعة (خلال 10 ثوانٍ). نفّذ الأعمال البطيئة، كإرسال البريد، في مهمة خلفية. - تصرّف حسب
type. في المدفوعات، يُستحسن أن تبحث عن طلبك عبرdata.object.referenceأوdata.object.idوأن تتحقق منamountوcurrency.
switch (event.type) {
case 'payment.succeeded':
await markOrderPaid(event.data.object.reference, event.data.object.id); // idempotent
break;
case 'payment.failed':
case 'payment.canceled':
// Not final: the customer can still pay at the same checkout_url until expires_at.
await noteFailedAttempt(event.data.object.reference, event.data.object.failure_message);
break;
case 'payment.expired':
await markOrderUnpaid(event.data.object.reference); // never overwrite an order that is already paid
break;
case 'refund.succeeded':
await recordRefund(event.data.object.payment_id, event.data.object.amount);
break;
default:
// Ignore event types you don't use. New types may be added.
break;
}إعادة المحاولة
ينجح التسليم عندما ترد نقطة النهاية بأي رمز 2xx خلال 10 ثوانٍ. أي شيء آخر (رمز 3xx أو 4xx أو 5xx، أو انتهاء المهلة، أو خطأ في الاتصال أو TLS) يُعد فشلًا، وتعيد تيرا باي المحاولة بفواصل متزايدة:
| المحاولة | التأخير بعد المحاولة السابقة |
|---|---|
| 1 | فورًا |
| 2 | دقيقة واحدة |
| 3 | 5 دقائق |
| 4 | 30 دقيقة |
| 5 | ساعتان |
| 6 | 6 ساعات |
| 7 | 12 ساعة |
| 8 | 24 ساعة |
بعد فشل 8 محاولات (نحو 45 ساعة) يُعلَّم التسليم بأنه فاشل، ويمكنك إعادة إرساله من لوحة التحكم.
لا تُتبع عمليات إعادة التوجيه، لذا وجّه نقطة النهاية إلى الرابط النهائي. وتُوقَّع كل محاولة بطابع زمني جديد.
الترتيب والتكرار
قد تصل الأحداث بغير ترتيبها، وفي حالات نادرة أكثر من مرة. وقد تُرسل عملية الدفع payment.failed ثم payment.succeeded لاحقًا عندما يحاول العميل مجددًا. استخدم Teyra-Event-Id لتجاهل المكرر، وعندما يهمك الترتيب اجلب أحدث حالة عبر GET /v1/payments/:id.
الاختبار من لوحة التحكم
في المطورون ← Webhooks، افتح نقطة نهاية واضغط إرسال حدث تجريبي. ترسل تيرا باي حدث payment.succeeded موقّعًا إلى الرابط، فتتأكد من التحقق من التوقيع ومن استجابة خادمك.
تعرض قائمة عمليات التسليم في الصفحة نفسها كل محاولة: نوع الحدث، والحالة (pending أو succeeded أو failed)، وعدد المحاولات، ورمز HTTP الذي أعاده خادمك، وبداية جسم استجابتك، وموعد المحاولة التالية. اضغط إعادة المحاولة لإرسال التسليم فورًا.
لاستلام الـ Webhooks على جهازك أثناء التطوير، اكشف خادمك المحلي عبر أداة أنفاق (مثل ngrok http 3000) وسجّل رابط HTTPS العام كنقطة نهاية في وضع الاختبار. بعدها نفّذ مدفوعات تجريبية، وكل واحدة منها ترسل أحداث payment.* حقيقية.
تدوير السر
افتح نقطة النهاية في لوحة التحكم واضغط تدوير السر. يسري السر الجديد فورًا، فحدّث إعدادات خادمك مباشرة.