PesaBridge
التوثيق/التشغيل الفعلي/Webhooks

التشغيل الفعلي

Webhooks

تسليمات أحداث موقعة ومعادة المحاولة: نقاط النهاية، وأنواع الأحداث، والتحقق بأربع لغات، والاختبار وإعادة التشغيل.

6 دقائق قراءة

في هذه الصفحة
  1. نقاط النهاية
  2. أنواع الأحداث
  3. كيف يبدو التسليم
  4. تحقق من كل تسليم
  5. إعادة المحاولة والتكرار
  6. الاختبار وإعادة التشغيل

نقاط النهاية

أنشئ نقطة نهاية أو أكثر باستخدام POST /partner/webhooks/endpoints (name وurl وevents كقائمة مفصولة بفواصل أو *، وmode). تحصل كل نقطة على سر توقيع خاص بها، يظهر مرة واحدة عند الإنشاء. عدّلها واحذفها واعرضها عبر استدعاءات /partner/webhooks/endpoint… أو في وحدة التحكم.

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

الحدثيُرسل عندما
charge.createdأُنشئ خصم عبر طلب الدفع.
charge.completedوافق العميل وانتقلت الأموال.
charge.declinedرفض العميل الطلب.
charge.expiredانتهت صلاحية الطلب دون رد.
checkout.completedدُفعت جلسة في صفحة الدفع المستضافة.
c2b.confirmationدفع عميل مباشرة إلى صندوقك أو رقم فاتورتك.

كيف يبدو التسليم

الترويسةالقيمة
X-PesaBridge-Eventنوع الحدث، مثل charge.completed.
X-PesaBridge-SignatureHMAC-SHA256 بالنظام الست عشري لنص الطلب الخام، بمفتاح سر التوقيع لنقطة النهاية.
X-PesaBridge-Timestampوقت Unix لتوقيع التسليم.
X-PesaBridge-Signature-V2t=<timestamp>,v1=<hex HMAC-SHA256 of "<timestamp>.<raw body>">: مقاوم لإعادة الإرسال.
X-PesaBridge-Deliveryمعرّف التسليم: سجّله واستخدمه لتجاهل النسخ المكررة.

تحقق من كل تسليم

احسب HMAC على البايتات التي استلمتها كما هي، قبل تحليل JSON، وقارن في زمن ثابت. فضّل V2 وارفض الطوابع الزمنية الأقدم من خمس دقائق.

Node.js
import crypto from "node:crypto";
// Express: app.post("/webhook", express.raw({ type: "application/json" }), handler)
function verified(req, secret) {
  const [t, v1] = (req.get("X-PesaBridge-Signature-V2") || "").split(",").map((p) => p.split("=")[1]);
  if (!t || Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const want = crypto.createHmac("sha256", secret).update(`${t}.${req.body}`).digest("hex");
  return v1?.length === want.length && crypto.timingSafeEqual(Buffer.from(v1), Buffer.from(want));
}
Python
import hmac, hashlib, time

def verified(raw_body: bytes, headers, secret: str) -> bool:
    parts = dict(p.split("=", 1) for p in headers.get("X-PesaBridge-Signature-V2", "").split(",") if "=" in p)
    t, v1 = parts.get("t"), parts.get("v1", "")
    if not t or abs(time.time() - int(t)) > 300:
        return False
    want = hmac.new(secret.encode(), f"{t}.".encode() + raw_body, hashlib.sha256).hexdigest()
    return hmac.compare_digest(v1, want)
PHP
<?php
$raw = file_get_contents("php://input");
parse_str(str_replace(",", "&", $_SERVER["HTTP_X_PESABRIDGE_SIGNATURE_V2"] ?? ""), $sig);
$ok = isset($sig["t"], $sig["v1"]) && abs(time() - (int)$sig["t"]) <= 300
   && hash_equals(hash_hmac("sha256", $sig["t"] . "." . $raw, getenv("PB_WHSEC")), $sig["v1"]);
http_response_code($ok ? 200 : 401);
Go
package webhook

import ("crypto/hmac"; "crypto/sha256"; "encoding/hex")

// Verified checks the V1 signature: hex HMAC-SHA256 of the raw body.
func Verified(raw []byte, sig, secret string) bool {
    m := hmac.New(sha256.New, []byte(secret))
    m.Write(raw)
    return hmac.Equal([]byte(hex.EncodeToString(m.Sum(nil))), []byte(sig))
}

إعادة المحاولة والتكرار

أجب بأي رمز 2xx خلال 10 ثوانٍ. وأي رد آخر أو انتهاء مهلة يؤدي إلى إعادة المحاولة بتأخير أسي (1 و2 و4 و8 و16 دقيقة، حتى 6 محاولات)، وبعدها يوسم التسليم بالحالة failed. وبسبب إعادة المحاولة قد يصل الحدث نفسه مرتين: اجعل المعالج لديك مانعًا للتكرار بناءً على X-PesaBridge-Delivery أو charge_ref.

نسلّم فقط إلى عناوين HTTPS العامة. وتُرفض عناوين الشبكات الخاصة والداخلية.

الاختبار وإعادة التشغيل

  • يرسل POST /partner/webhooks/test حدثًا اختباريًا إلى نقطة نهاية.
  • يعرض GET /partner/webhooks/deliveries التسليمات الأخيرة مع رمز الحالة وعدد المحاولات.
  • يعيد POST /partner/webhooks/resend تشغيل تسليم بعد إصلاح المعالج لديك.
  • يلتقط مستقبِل Echo (GET /partner/echo/url) التسليمات ويتحقق منها تلقائيًا دون خادم خاص بك.

يجيب مهندسونا عن أسئلة الربط. أرسل إلينا مرجع الطلب وسنجد الاستدعاء بالضبط.

تواصل مع الدعم