@xpayeg/sdk
الـ JavaScript SDK بتاع المتصفّح. مرجع لكل تصدير عام، وتوقيع دالة، ونوع خيار.
الـ JavaScript SDK بتاع XPay مكتبة صغيّرة بتتحمّل من الـ CDN، وبتديك XPayInstance مكتوب بالأنواع من مفتاحك القابل للنشر. ومنها تقدر تركّب واجهة دفع كـ Elements، أو تفتح drop-in checkout، أو تشغّل initCheckout باستدعاء واحد وتأكّد دفعة.
pnpm add @xpayeg/sdk
# or: npm install @xpayeg/sdk / yarn add @xpayeg/sdkالـ package بيوفّر بناءات ESM وCJS، زائد أنواع TypeScript كاملة. وقت التشغيل نفسه بيتحمّل عند الطلب من https://checkout.xpay.app/v1/sdk.js.
فيه طريقتين لتحميل الـ SDK، وكل واحدة بتعرض الـ factory باسم مختلف. ده أكتر غلط شائع في التكامل، فخلّيك مظبّطه من البداية:
// استورد loadXPay واعمله await. ده المسار اللي باقي الصفحة بتوثّقه.
import { loadXPay } from "@xpayeg/sdk";
const xpay = await loadXPay("pk_test_...");<!-- حطّ الـ CDN script tag، وبعدين استدعي الـ factory العام XPay() اللي الـ runtime
بيحطّه على window. من غير import، ولا await، ولا build step. -->
<script src="https://checkout.xpay.app/v1/sdk.js"></script>
<script>
const xpay = XPay("pk_test_...");
</script>loadXPay موجود بس في الـ package بتاع npm؛ والـ CDN runtime بيعرض بس الـ global XPay. مش قابلين للتبديل: استدعاء loadXPay(...) بعد الـ script tag بيرمي ReferenceError: loadXPay is not defined، والـ global XPay مش قابل للاستيراد. اختار الصف اللي يناسب الإعداد بتاعك؛ أي حاجة بعد ما تحصل على نسخة xpay هي نفسها بالظبط. الصفحة دي بتوثّق مدخل npm (loadXPay). على مسار الـ HTML العادي، بدّل await loadXPay(k) بـ XPay(k) في أي مثال تحت.
شوفه شغّال: مثال HTML عادي
كل نمط في الصفحة دي كملفات HTML عادية جاهزة للتشغيل: CDN script tag + الـ factory العام XPay()،
وسيرفر Express صغيّر، من غير build step. اعمل clone، وحطّ مفاتيح الاختبار، وافتح في المتصفّح.
الصفحة دي مرجع لكل تصدير عام. للشروحات، شوف Drop-in وElements تحت Integrate.
استخدم الـ package ده لما
@xpayeg/sdk هو الـ SDK الـ vanilla وهو الاختيار الصح كل ما تكون مش على React. ده بيغطي:
- HTML العادي والمواقع الثابتة (الـ CDN script tag + الـ factory العام
XPay()؛ شوف مساري التحميل فوق). - Vue، وSvelte، وSolid، وAngular، وLit، وQwik، وAstro، وأي إطار تاني. استدعي الـ SDK من جوّه دورة حياة مكوّن الإطار ده (mount، وonMount، وما يعادل useEffect، إلخ).
- React Native عن طريق WebView لحد ما ينزل package أصلي.
- سكربتات من ناحية السيرفر محتاجة تكتب حمولات الـ
clientSecretبالأنواع (أنواع TypeScript بتاعة الـ package مستقلة عن الإطار).
لـ React، @xpayeg/react غلاف راحة رفيع فوق الـ package ده. مبني على loadXPay، وxpay.initCheckout، وxpay.elements، فأي حاجة بتقراها هنا بتنطبق تحت الكواليس هناك كمان.
البداية السريعة
المسار المنصوح بيه هو loadXPay على مستوى الموديول، وبعدين xpay.initCheckout() بمجرد ما يبقى عندك clientSecret من السيرفر بتاعك.
import { loadXPay } from "@xpayeg/sdk";
// Module-level: call once, share across the app.
const xpayPromise = loadXPay("pk_test_...");
async function startCheckout() {
const xpay = await xpayPromise;
if (!xpay) return; // SSR returns null on the server
// initCheckout accepts a Promise<string> too, so you can pass the fetch directly.
const checkout = await xpay.initCheckout({
clientSecret: fetch("/api/create-checkout", { method: "POST" })
.then((r) => r.json())
.then((d) => d.clientSecret as string),
});
// Mount the payment element.
const elements = checkout.getElements();
const paymentElement = elements.create("payment");
paymentElement.mount("#payment-element");
// Listen for state changes (promo codes, quantity updates, fee recalcs).
checkout.on("change", (session) => {
document.getElementById("total")!.textContent =
`${session.currency} ${(session.amountTotal / 100).toFixed(2)}`;
});
// Confirm when the customer submits.
document.getElementById("pay")!.addEventListener("click", async () => {
const result = await checkout.confirm({
customerDetails: { email: "customer@example.com", name: "Aya Hassan" },
});
if (result.type === "error") {
console.error(result.error.message);
return;
}
window.location.href = "/thank-you";
});
}التصديرات بنظرة سريعة
| التصدير | النوع | يعني إيه |
|---|---|---|
loadXPay(publishableKey) | function | بيحمّل الـ SDK من الـ CDN ويرجّع XPayInstance (أو null على السيرفر أثناء الـ SSR). |
XPayInstance | interface | الـ factory بتاع Elements، وdrop-in Checkout، وconfirmPayment، وinitCheckout. |
Elements | interface | بيدير الـ payment elements (PaymentElement) ودورة حياة الجلسة. |
PaymentElement | interface | مختار وسيلة دفع قابل للتركيب مع فورم البطاقة، وBNPL، وكشك، ووسائل المحفظة. |
ConfirmPaymentOptions | interface | الشكل المُمرَّر لـ xpay.confirmPayment() وcheckout.confirm(). |
CheckoutOptions | interface | إعداد xpay.checkout(). drop-in modal أو inline embed. |
CheckoutInstance | interface | مقبض الـ drop-in checkout: open()، وclose()، وdestroy()، زائد الأحداث. |
CheckoutCompleteResult | interface | الحمولة لـ onComplete callback بتاع الـ drop-in. |
InitCheckoutOptions | interface | خيارات xpay.initCheckout(). الـ API العصري باستدعاء واحد. |
InitCheckoutResult | type | بيانات الجلسة مدموجة مع دوال الإجراءات (confirm، وأكواد الخصم، إلخ). |
CheckoutActions | interface | دوال الإجراءات اللي بتركب على كائن الـ checkout. |
CheckoutSession | type | شكل بيانات الجلسة: المبلغ، والعملة، والحالة، ووسائل الدفع، والبنود. |
ActionResult | type | tagged union: { type: "success", session } أو { type: "error", error }. |
XPayError | interface | نوع الخطأ الموحَّد عبر كل إجراء في الـ SDK. |
Appearance | type | تجاوزات العلامة التجارية للواجهة المضمّنة (وضع اللون، ونمط الحدّ، والألوان، والخط). |
PaymentElementChangeEvent | interface | الحمولة لأحداث الـ change بتاعة PaymentElement. |
ElementsReadyEvent | interface | الحمولة لحدث "ready" بتاع Elements. |
ElementsLoadErrorEvent | interface | الحمولة لحدث "loaderror" بتاع Elements. |
CustomerDetails, Address | interface | الأشكال لحقول العميل اللي فورمك بيجمّعها وبتتمرّر وقت التأكيد. |
PaymentMethodInfo | type | معلومات عن وسيلة دفع متاحة على الجلسة. |
SessionStatus | type | tagged union: open، أو expired، أو complete. |
loadXPay(publishableKey)
بيحمّل وقت تشغيل الـ SDK من الـ CDN ويرجّع XPayInstance. استدعيه مرة واحدة على مستوى الموديول، مش جوّه مكوّن.
import { loadXPay } from "@xpayeg/sdk";
const xpayPromise = loadXPay("pk_test_...");
// later, when you have a clientSecret:
const xpay = await xpayPromise;
const elements = xpay.elements({ clientSecret: "cs_test_..." });| البارامتر | النوع | الوصف |
|---|---|---|
publishableKey | string | مفتاح الـ API القابل للنشر بتاعك (pk_test_... أو pk_live_...). |
بيرجّع Promise<XPayInstance | null>. الـ null بيرجع أثناء العرض من ناحية السيرفر (مفيش window). الـ XPayProvider من @xpayeg/react بيتعامل مع الـ null بسلاسة بإعادة المحاولة على العميل.
وقت التشغيل بيتجاب مرة واحدة؛ واستدعاءات loadXPay اللي بعدها بتعيد استخدام نفس الـ script tag. لو فيه سكربت بـ sdk.js موجود أصلًا على الصفحة، ما بيتحقنش تاني.
XPayInstance
الـ factory اللي بيرجعلك من loadXPay. أربع دوال.
interface XPayInstance {
elements(options: ElementsOptions): Elements;
checkout(options: CheckoutOptions): CheckoutInstance;
confirmPayment(options: ConfirmPaymentOptions): Promise<ActionResult>;
initCheckout(options: InitCheckoutOptions): Promise<InitCheckoutResult>;
}elements(options)
بينشئ نسخة Elements لواجهة دفع مخصّصة. مرّر له الـ clientSecret من جلسة دفع.
const elements = xpay.elements({
clientSecret: "cs_test_...",
appearance: { colorMode: "dark", borderStyle: "rounded" },
locale: "en",
});ElementsOptions:
| الحقل | النوع | الوصف |
|---|---|---|
clientSecret | string | Promise<string> | مطلوب. الـ client secret بتاع جلسة الدفع. ممكن يكون Promise. |
appearance | Appearance | اختياري. تجاوزات الواجهة المدموجة مع العلامة التجارية من ناحية السيرفر للجلسة. |
locale | "en" | "ar" | اختياري. الافتراضي "en". |
checkout(options)
بينشئ نسخة drop-in checkout. شوف CheckoutOptions تحت.
confirmPayment(options)
بيقدّم دفعة باستخدام البيانات اللي Elements جمّعها. شوف ConfirmPaymentOptions تحت.
initCheckout(options)
الـ API العصري باستدعاء واحد: بيرجّع بيانات الجلسة ودوال الإجراءات مع بعض. شوف InitCheckoutOptions تحت.
Elements
بيرجعه xpay.elements(). بيدير iframe دفع مشترك واحد وبيكشف دوال تعديل الجلسة.
interface Elements {
create(type: "payment"): PaymentElement;
getElement(type: "payment"): PaymentElement | null;
fetchPaymentMethods(): Promise<PaymentMethodInfo[]>;
on(event: "ready" | "change" | "loaderror" | "error", handler): void;
off(event: string, handler): void;
applyPromotionCode(code: string): Promise<ActionResult>;
removePromotionCode(): Promise<ActionResult>;
updateLineItemQuantity(args: { lineItem: string; quantity: number }): Promise<ActionResult>;
submit(): Promise<{ error?: XPayError; selectedPaymentMethod?: string }>;
fetchUpdates(): Promise<ActionResult>;
changeAppearance(appearance: Appearance): void;
destroy(): void;
}الأحداث
| الحدث | توقيع الـ handler | بيطلق لما |
|---|---|---|
"ready" | (data: ElementsReadyEvent) => void | الجلسة اتحمّلت والـ elements قابلة للتركيب. بيطلق فورًا لو متحمّلة أصلًا. |
"change" | (session: CheckoutSession) => void | بيانات الجلسة بتتغيّر (اختيار وسيلة دفع، وأكواد خصم، وإعادة حساب رسوم). |
"loaderror" | (data: ElementsLoadErrorEvent) => void | الجلسة بتفشل في التحميل (خطأ شبكة، أو client secret غلط، أو خطأ API). |
"error" | (error: XPayError) => void | خطأ غير مطلوب مش جاي من إجراء التاجر (مثلًا جلسة انتهت أثناء إعادة حساب رسوم). |
الدوال
create("payment", options?): بيرجّعPaymentElementتقدر تركّبه.getElement("payment"): بيرجّع الـ element الموجود أوnullلو ما اتعملش واحد.fetchPaymentMethods(): بيرجّع قائمة الـPaymentMethodInfoاللي الجلسة بتدعمها.applyPromotionCode(code): بيطبّق كود خصم، ويرجّعActionResult.removePromotionCode(): بيشيل الكود المطبَّق، ويرجّعActionResult.updateLineItemQuantity({ lineItem, quantity }): بيحدّث بند، ويرجّعActionResult.submit(): بيتحقّق من حقول الـ element. بيرجّع يا إماerrorأو نص نوع الـselectedPaymentMethod.fetchUpdates(): بيعيد جلب الجلسة من السيرفر.changeAppearance(appearance): بيحدّث العلامة التجارية في وقت التشغيل من غير ما يعيد إنشاء الـ elements.destroy(): بيفكّك النسخة ويحرّر الموارد.
PaymentElement
مختار وسيلة الدفع الكامل مع فورم البطاقة، وBNPL، وكشك، ووسائل المحفظة. خُد واحد من elements.create("payment").
interface PaymentElement {
mount(container: string | HTMLElement): void;
unmount(): void;
destroy(): void;
focus(): void;
blur(): void;
collapse(): void;
on(event: "ready" | "loaderstart" | "loaderror", handler): void;
off(event: string, handler): void;
}PaymentElementChangeEvent هو الحمولة لحدث "change" بتاع الـ Elements الأب لما يتطلق من تغيير وسيلة دفع:
| الحقل | النوع | الوصف |
|---|---|---|
elementType | "payment" | دايمًا "payment" للـ element ده. |
empty | boolean | إذا كانت كل حقول البطاقة فاضية. |
complete | boolean | إذا كان الفورم مكتمل وجاهز للتقديم. |
collapsed | boolean | إذا كان مختار الوسيلة مطوي (مفيش وسيلة مختارة). |
value | { type: string } | نوع وسيلة الدفع المختارة حاليًا. |
session | CheckoutSession | آخر لقطة للجلسة. |
ConfirmPaymentOptions
الشكل المُمرَّر لـ xpay.confirmPayment() وcheckout.confirm().
| الحقل | النوع | الوصف |
|---|---|---|
elements | Elements | مطلوب (لـ xpay.confirmPayment). نسخة الـ Elements اللي بتدير الفورم. checkout.confirm بيحقنها لك. |
customerDetails | CustomerDetails | اختياري. حقول العميل اللي فورمك جمّعها. |
customFields | Record<string, string | number | boolean> | اختياري. قيم الحقول المخصّصة للجلسة. |
deviceFingerprint | { visitorId: string; confidence?: number } | اختياري. بصمة الجهاز لكشف الاحتيال. |
paymentMethod | string | اختياري. تجاوز نوع وسيلة الدفع المختارة. |
redirect | "if_required" | "always" | الافتراضي "if_required". بيتحكم في التنقّل بعد الدفع. |
returnUrl | string | اختياري. تجاوز afterCompletion.redirect.url بتاع الجلسة. |
دلالات redirect:
"if_required"بيرجّع النتيجة لكودك؛ وبيحوّل بس لما وسيلة الدفع تتطلّب كده (مثلًا 3-D Secure، وBNPL)."always"بيحوّل دايمًا لـreturnUrlبعد الدفع. الصفحة بتتنقّل بعيد والدالة عمرها ما بترجع عند النجاح.
CheckoutOptions
إعداد الـ drop-in xpay.checkout().
| الحقل | النوع | الوصف |
|---|---|---|
clientSecret | string | مطلوب. الـ client secret بتاع جلسة الدفع. |
mode | "modal" | "inline" | "modal" (افتراضي) بيعرض تغطية؛ و"inline" بيضمّن في container. |
container | string | HTMLElement | مطلوب لوضع inline. CSS selector أو DOM node علشان يتضمّن فيه. |
appearance | Appearance | تجاوزات الواجهة المدموجة مع العلامة التجارية للجلسة. |
locale | "en" | "ar" | لغة الواجهة. الافتراضي "en". |
onComplete | (result: CheckoutCompleteResult) => void | بيتنادى لما الدفعة تكتمل بنجاح. |
onClose | () => void | بيتنادى لما النافذة المنبثقة تتقفل. |
onReady | (session: CheckoutSession) => void | بيتنادى لما الجلسة تتحمّل والواجهة تجهز. |
onConfirmed | () => void | بيتنادى لما العميل يأكّد الدفع، قبل النتيجة النهائية. |
onError | (error: CheckoutError) => void | بيتنادى لما يحصل خطأ. |
CheckoutInstance
بيرجعه xpay.checkout(). مقبض أمري.
interface CheckoutInstance {
open(): void; // modal mode
close(): void;
destroy(): void;
on(event: "complete" | "close" | "ready" | "confirmed" | "error", handler): void;
off(event: string, handler): void;
}CheckoutCompleteResult (الحمولة لـ onComplete):
| الحقل | النوع | الوصف |
|---|---|---|
status | "succeeded" | دايمًا "succeeded" للـ callback ده. |
paymentIntentId | string | معرّف الـ Payment Intent للتحقق من ناحية السيرفر. |
chargeId | string | اختياري. معرّف الـ Charge، لما يكون متاح. |
redirectUrl | string | اختياري. URL التحويل بعد الاكتمال بتاع الجلسة. |
InitCheckoutOptions
الـ API العصري باستدعاء واحد. بيدمج elements() مع تحميل الجلسة، وبيكشف بيانات الجلسة زائد دوال الإجراءات على كائن واحد.
const checkout = await xpay.initCheckout({ clientSecret: "cs_test_..." });
console.log(checkout.amountTotal); // session field
const result = await checkout.confirm({ customerDetails: { email } });| الحقل | النوع | الوصف |
|---|---|---|
clientSecret | string | Promise<string> | مطلوب. الـ client secret بتاع الجلسة. |
appearance | Appearance | اختياري. تجاوزات الواجهة. |
locale | "en" | "ar" | اختياري. الافتراضي "en". |
InitCheckoutResult هو CheckoutSession & CheckoutActions. دوال الإجراءات على CheckoutActions:
| الدالة | بتعمل إيه |
|---|---|
confirm(options?) | بتأكّد الدفعة. بترجّع ActionResult. |
applyPromotionCode(code) | بتطبّق كود. بترجّع ActionResult. |
removePromotionCode() | بتشيل الكود المطبَّق. بترجّع ActionResult. |
updateLineItemQuantity({ lineItem, quantity }) | بتحدّث كمية بند. بترجّع ActionResult. |
submit() | بتتحقّق من الحقول. بترجّع { error?, selectedPaymentMethod? }. |
fetchUpdates() | بتعيد جلب الجلسة من السيرفر. بترجّع ActionResult. |
changeAppearance(appearance) | بتحدّث العلامة التجارية في وقت التشغيل. |
on(event, handler) | تستنى "change"، أو "error"، أو حدث مخصّص. |
getElements() | بترجّع الـ Elements الأساسي لإنشاء الـ elements. |
CheckoutSession (نوع بيانات)
بيانات الجلسة المكشوفة للتاجر. مشتقّة من رد السيرفر، مقصوصة على الحقول الموجّهة للتاجر.
| الحقل | النوع | الوصف |
|---|---|---|
id | string | معرّف الجلسة cs_*. |
amountSubtotal | number | المجموع الفرعي بالوحدات الصغرى (مثلًا 50000 لـ 500.00 EGP). |
amountTotal | number | الإجمالي بالوحدات الصغرى بعد الرسوم والضرايب والخصومات. |
currency | string | كود العملة ISO (مثلًا "EGP"). |
merchantName | string | الاسم المعروض لنشاطك التجاري. |
livemode | boolean | true للمفاتيح الفعلية؛ وfalse لوضع الاختبار. |
expiresAt | string | طابع زمني ISO لوقت انتهاء الجلسة. |
status | SessionStatus | tagged union: open، وexpired، وcomplete. |
canConfirm | boolean | إذا كانت الجلسة ممكن تتأكّد حاليًا. |
paymentMethods | PaymentMethodInfo[] | وسائل الدفع المتاحة على الجلسة دي. |
lineItems | CheckoutLineItem[] | البنود. |
totalDetails | CheckoutTotalDetails | تفصيل المجموع الفرعي، والضريبة، والشحن، والخصم. |
fees | CheckoutFees | تفصيل الرسوم لما يكون feesPassThrough مفعّل. |
discounts | CheckoutDiscount[] | أكواد الخصم المطبَّقة. |
SessionStatus:
type SessionStatus =
| { type: "open" }
| { type: "expired" }
| { type: "complete"; paymentStatus: "paid" | "unpaid" | "no_payment_required" };PaymentMethodInfo:
| الحقل | النوع | الوصف |
|---|---|---|
type | string | نوع الوسيلة ("card"، "valu"، "fawry"). |
displayName | string | لافتة مترجمة ("Card"، "ValU"، "Fawry"). |
category | "card" | "bnpl" | "kiosk" | "wallet" | تصنيف لتجميع الواجهة. |
icon | string | URL أيقونة اختياري. |
nextActionText | string | اختياري. وصف الخطوة الجاية اللي بتظهر للعميل. |
ActionResult وXPayError
كل إجراء بيعدّل الجلسة بيرجّع ActionResult. ده tagged union، فضيّق حسب result.type قبل ما تقرا الحمولة.
type ActionResult<E = XPayError> =
| { type: "success"; session: CheckoutSession }
| { type: "error"; error: E };XPayError هو شكل الخطأ الموحَّد. الحقول الخاصة بالدفع بتبقى null للأخطاء اللي مش دفع.
| الحقل | النوع | الوصف |
|---|---|---|
type | string | فئة الخطأ: "card_error"، "invalid_request_error"، "api_error". |
code | string | null | كود قابل للقراءة آليًا ("card_declined"، "promotion_code_not_found"). |
message | string | رسالة مقروءة للبني آدم. |
param | string | null | البارامتر اللي سبّب الخطأ (مثلًا "promotionCode"). |
docUrl | string | null | URL التوثيق لكود الخطأ ده. |
declineCode | string | null | تفصيل الرفض زي "insufficient_funds". Null للأخطاء اللي مش دفع. |
adviceCode | string | null | نصيحة إعادة المحاولة: "try_again_later"، "do_not_try_again"، "confirm_card_data". |
chargeId | string | null | معرّف الـ charge الفاشل. |
paymentMethodId | string | null | معرّف وسيلة الدفع الفاشلة. |
paymentMethodType | string | null | نوع وسيلة الدفع ("card"، "valu"). |
paymentMethod | Record<string, unknown> | null | لقطة وسيلة الدفع وقت الفشل. |
لدليل التعامل مع أخطاء الـ API وفضاءات أكواد الخطأ التلاتة، شوف الأخطاء، وأكواد أخطاء الـ API، وأكواد أخطاء الدفع، وأكواد الرفض.
Appearance
تجاوزات العلامة التجارية للواجهة المضمّنة. بتعكس مجموعة فرعية من حقول التاجر الافتراضية اللي بتظبطها في إعدادات العلامة التجارية.
| الحقل | القيم |
|---|---|
colorMode | "system" | "light" | "dark" |
borderStyle | "rounded" | "sharp" | "pill" |
spacing | "condensed" | "normal" | "spacious" |
inputSize | "small" | "medium" | "large" |
inputStyle | "outlined" | "flat" | "filled" |
formLayout | "compact" | "spacious" |
colors | كائن بـ اتناشر رمز دلالي (primary، وforeground، وbackground، وmuted، وaccent، وborder، وinput، وring، وdestructive، زائد أزواج الـ foreground). |
fontFamily | نص CSS لـ font-family. |
مرّر Appearance لـ xpay.elements()، أو xpay.checkout()، أو xpay.initCheckout(). أو استدعي elements.changeAppearance() / checkout.changeAppearance() علشان تحدّث في وقت التشغيل.
CustomerDetails وAddress
الأشكال لحقول العميل اللي بتجمّعها على فورمك وبتمرّرها وقت التأكيد.
interface CustomerDetails {
email?: string;
name?: string;
phone?: string;
billingDetails?: { name?: string; email?: string; phone?: string; address?: Address };
shipping?: { name?: string; phone?: string; address?: Address };
}
interface Address {
line1?: string;
line2?: string;
city?: string;
state?: string;
postalCode?: string;
country?: string;
}للمرجع المتبادل من ناحية المطوّر عن كل حقل في جلسة الدفع بيتحكم في إيه (مفاتيح التحصيل، والحقول المخصّصة، وأولوية الملء المسبق)، شوف دورة حياة العميل.