الـ 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-Typeapplication/json
Teyra-Signaturet=1730124420,v1=5f2b…. راجع التحقق من التواقيع.
Teyra-Event-Idمعرّف الحدث، وهو نفسه id في الجسم. استخدمه لتجاهل التكرار.
User-AgentTeyraPay-Webhooks/1.0

معالجة الحدث

  1. اقرأ جسم الطلب الخام.
  2. تحقّق من التوقيع، وارفض الطلب بالرمز 400 إذا لم يتطابق.
  3. إذا عالجت Teyra-Event-Id هذا من قبل، أعِد 200 وتوقف.
  4. أعِد رمزًا من فئة 2xx بسرعة (خلال 10 ثوانٍ). نفّذ الأعمال البطيئة، كإرسال البريد، في مهمة خلفية.
  5. تصرّف حسب 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دقيقة واحدة
35 دقائق
430 دقيقة
5ساعتان
66 ساعات
712 ساعة
824 ساعة

بعد فشل 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.* حقيقية.

تدوير السر

افتح نقطة النهاية في لوحة التحكم واضغط تدوير السر. يسري السر الجديد فورًا، فحدّث إعدادات خادمك مباشرة.