API الاشتراكات: الزبناء والاشتراك والويب هوك والاختبار خطوة بخطوة
API الاشتراكات: إنشاء الزبون والاشتراك، ورابط دفع لكل استحقاق، وأحداث الويب هوك، والإيقاف والاستئناف والإلغاء، والاختبار في السندبوكس.
تُختصر API الاشتراكات لدى ChariPay في عمليتَي إنشاء وثلاثة أحداث: تنشئون زبونًا (POST /v1/clients)، ثم اشتراكًا لهذا الزبون (POST /v1/subscriptions)؛ وعند كل استحقاق، تولّد ChariPay رابط دفع لاستعمال واحد وترسله بالبريد الإلكتروني إلى زبونكم، فيؤدّيه في الصفحة المستضافة بالبطاقة مع 3-D Secure؛ ويصلكم كل استحقاق مؤدّى عبر ويب هوك موقَّع. يعرض هذا الدليل كل خطوة بنداءات مُتحقَّق منها مقابل عقد API: الحقول الإلزامية والاختيارية، ورابط الدفع الأول، والتذكيرات، وأحداث subscription.*، وتدبير دورة الحياة، وIdempotency، والأخطاء، وخطة اختبار في السندبوكس.
API الاشتراكات: النموذج
ChariPay منصة دفع مغربية، مزوّد خدمات دفع (PSP) تشغّله Chari Money، مؤسسة أداء مرخَّصة من بنك المغرب. وتتعامل وحدة الاشتراكات فيها مع ثلاثة كائنات:
| الكائن | نقطة النهاية الرئيسية | ما يحمله |
|---|---|---|
| الزبون | POST /v1/clients | الاسم، والبريد الإلكتروني — العنوان الذي تُرسل إليه روابط الدفع —، والهاتف |
| الاشتراك | POST /v1/subscriptions | المبلغ، والدورية، والتواريخ، والحالة، وmetadata |
| الاستحقاقات | GET /v1/subscriptions/{reference}/charges | كل استحقاق مُولَّد — رابط دفع لاستعمال واحد لكل فترة، مع حالته status ورابطه payUrl —، الأحدث أولًا |
ويُختصر المبدأ في جملة واحدة: اشتراك ChariPay سلسلة من روابط الدفع. في تاريخ الاستحقاق الأول (startDate)، ثم في كل فترة حسب الدورية، تنشئ ChariPay رابط دفع لاستعمال واحد خاصًا بالفترة وترسله بالبريد الإلكتروني إلى زبونكم، في رسالة يحمل موضوعها وصف الاشتراك. يفتح زبونكم الرابط ويؤدّي في الصفحة المستضافة، بالبطاقة مع 3-D Secure. وما دام الاستحقاق غير مؤدّى، يُرسل إليه تذكير بالأداء بالبريد الإلكتروني كل يوم، بالرابط نفسه، ولا تُفتح أي فترة جديدة: فالاستحقاقات غير المؤداة لا تتراكم.
وتتبع حالة الاشتراك دورة بسيطة. من جهة API، هي قيم التعداد status، وهذه هي مع ما يقابلها بعبارة واضحة:
| القيمة في API | بعبارة واضحة | المعنى |
|---|---|---|
INCOMPLETE | غير نشط بعد | أُنشئ، ولم يُؤدَّ الاستحقاق الأول بعد |
ACTIVE | نشط | أُدّي الاستحقاق الأول (activatedAt محدَّد)؛ ويُرسل رابط عند كل استحقاق |
PAUSED | موقوف مؤقتًا | لا يُولَّد أي رابط جديد إلى حين الاستئناف |
COMPLETED | منتهٍ | بلغ تاريخ الانتهاء وأُدّي الاستحقاق الأخير |
CANCELED | ملغى | ألغيتموه بأنفسكم، أو بقي استحقاق غير مؤدّى بعد انقضاء مهلة 14 يومًا |
والأعراف هي أعراف API كلها: قاعدة واحدة، https://api-psp.charipay.ma، في السندبوكس كما في الإنتاج — والمفتاح هو ما يحدّد البيئة (chari_sk_test_… أو chari_sk_live_…)؛ والترويسة X-CHARI-PAY-API-KEY في كل طلب؛ وJSON بصيغة camelCase؛ والمبالغ بالدرهم، بالوحدات الرئيسية (149.90 = 149,90 درهمًا)؛ والحقول الاختيارية غائبة لا null أبدًا؛ والتعدادات بحروف كبيرة، وعلى شفرتكم أن تتقبّل قيمها الجديدة. والصورة العامة لـAPI في API الدفع في المغرب، والعرض من جهة النشاط في صفحة الاشتراكات والمدفوعات المتكررة.
ولتنفيذ النداءات التالية، تحتاجون إلى مفتاح chari_sk_test_…. يُفتح وضع الاختبار بمجرد تفعيل حسابكم، دون موافقة تنتظرونها: ابدؤوا في وضع الاختبار — ثلاثة حقول (الاسم، والبريد الإلكتروني المهني، والمؤسسة)، ورابط تفعيل يصلكم بالبريد لاختيار كلمة المرور، ثم بوابة التاجر حيث تنشئون بأنفسكم مفتاح الاختبار بعد إعادة مصادقة؛ ولا يُعرض المفتاح كاملًا إلا مرة واحدة. ادفعوا ببطاقة الاختبار 4918 9141 0719 5005، CVV 123، وأي تاريخ انتهاء مستقبلي، ورمز 3-D Secure 555: هذه البطاقة هي الوحيدة المقبولة، ولا يتحرك أي مال حقيقي. ويجري التحقق من مؤسستكم (KYB) بالتوازي ولا يشترطه إلا الانتقال إلى الإنتاج.
الخطوة 1: إنشاء الزبون
يرتبط الاشتراك دائمًا بزبون موجود. يُنشأ الزبون مرة واحدة ويُعاد استعماله: لاشتراك ثانٍ، أو لتغيير الصيغة.
curl -X POST 'https://api-psp.charipay.ma/v1/clients' \
-H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
-H 'Content-Type: application/json' \
-d '{
"name": "Amine Bennani",
"email": "amine.bennani@example.com",
"phone": "+212600000000"
}'لا يشترط مخطط الزبون إلا name. ومع ذلك، قدّموا email دائمًا حين سيُنشأ للزبون اشتراك: فإلى هذا العنوان يُرسل رابط الدفع الخاص بكل استحقاق، وتُرسل التذكيرات. وphone اختياري ويتبع صيغة E.164. ويحمل الرد 201 المعرّف id للزبون، وهو UUID: احفظوه في قاعدة بياناتكم بجانب معرّف الزبون الخاص بكم.
وتضمّ الوحدة خمسة نداءات: الإنشاء، والسرد (GET /v1/clients)، والقراءة (GET /v1/clients/{id})، والتحديث (PUT /v1/clients/{id})، المفيد لتصحيح عنوان بريد إلكتروني قبل الاستحقاق المقبل، والحذف (DELETE /v1/clients/{id})، الذي يُرفض ما دام للزبون اشتراكات نشطة. وتفاصيل الحقول في وحدة «الزبناء» في توثيق API.
الخطوة 2: إنشاء الاشتراك
يحمل الاشتراك الصيغة: المبلغ، والدورية، والتواريخ، وما ستحتاجونه للتعرف عليه في أحداث الويب هوك. ويضمّ العقد تسعة حقول، لا أكثر:
| الحقل | إلزامي | الصيغة والدور |
|---|---|---|
clientId | نعم | UUID الزبون المُنشأ في الخطوة 1 |
amount | نعم | مبلغ كل استحقاق، بالدرهم، بالوحدات الرئيسية |
description | نعم | تسمية تظهر على كل رابط دفع، 255 حرفًا على الأكثر |
frequency | نعم | DAILY أو WEEKLY أو MONTHLY أو YEARLY |
startDate | نعم | تاريخ الاستحقاق الأول، بصيغة YYYY-MM-DD |
channels | نعم | قناة إرسال روابط الدفع: ["EMAIL"] |
endDate | لا | تاريخ الانتهاء؛ ودونه يبقى الاشتراك مفتوح المدة |
externalId | لا | معرّف اشتراككم، فريد لكل حساب ولكل بيئة؛ ويجعل الإنشاء قابلًا للإعادة |
metadata | لا | كائن مسطَّح، 4 كيلوبايت على الأكثر، يُنقل إلى كل رابط دفع ويعود في كل أحداث الويب هوك الخاصة بالاشتراك |
curl -X POST 'https://api-psp.charipay.ma/v1/subscriptions' \
-H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
-H 'Content-Type: application/json' \
-d '{
"clientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"amount": 149.90,
"description": "Gold plan - monthly",
"frequency": "MONTHLY",
"startDate": "2026-11-01",
"channels": ["EMAIL"],
"externalId": "sub-cus-1001-gold",
"metadata": { "customerId": "cus_1001", "plan": "gold" }
}'يصف الرد 201 — أو 200 إن كان externalId موجودًا سلفًا — الاشتراكَ: مرجعه reference (sub_…) الذي تستعمله كل النداءات الموالية، وحالته status — INCOMPLETE لاشتراك أُنشئ للتو —، ومصدره origin (API، أو DASHBOARD لاشتراك أُنشئ من بوابة التاجر)، واستحقاقه المقبل (nextRunDate، وهو التاريخ الذي تُفتح فيه الفترة المقبلة ويُرسل رابطها بالبريد الإلكتروني)، ثم currentCharge متى كانت هناك فترة مفتوحة، وهو رابط الدفع الخاص بالفترة الجارية. وتُحتسب التواريخ على توقيت Africa/Casablanca. وفي metadata، ضعوا معرّفات مبهمة — رقم زبونكم، ورمز صيغتكم —، ولا تضعوا أبدًا بيانات بطاقة ولا معطيات شخصية زائدة. والمخطط الكامل في وحدة «الاشتراكات» في توثيق API.
الخطوة 3: رابط الدفع الأول والتذكيرات
يبقى الاشتراك المُنشأ حديثًا في الحالة INCOMPLETE ما دام استحقاقه الأول غير مؤدّى. وهذا الاستحقاق الأول رابط دفع كسائر الاستحقاقات: يتلقاه زبونكم بالبريد الإلكتروني ويؤدّيه في الصفحة المستضافة، بالبطاقة مع 3-D Secure. ولا يرى خادمكم أي بيانات بطاقة.
ويصف عقد API كيف يظهر هذا الاستحقاق الأول:
- إن كان `startDate` اليوم أو في الماضي، يُنشأ الرابط الأول فورًا ويُعاد في
currentCharge، وهو كائن رابط دفع يحملpayUrlالموجَّه إلى المشتري: يمكنكم توجيه زبونكم إليه بمجرد انتهاء تسجيله، دون انتظار أن يفتح بريده. - إن كان `startDate` في المستقبل، فلا يُنشأ أي رابط بعد: يُرسل الأول في ذلك التاريخ. أعيدوا حينها قراءة الاشتراك عبر
GET /v1/subscriptions/{reference}؛ فمتى فُتحت الفترة، يحملcurrentChargeالاستحقاق الجاري.
وبعد نجاح الأداء الأول، تنتقل الحالة إلى ACTIVE ويبيّن الحقل activatedAt متى تمّ ذلك. ثم يتكرر المسار نفسه عند كل استحقاق: رابط جديد، ورسالة بريد إلكتروني، وأداء في الصفحة المستضافة، وويب هوك.
وحين لا يُؤدّى استحقاق، يتلقى زبونكم تذكيرًا بالبريد الإلكتروني كل يوم، بالرابط نفسه. ولا تُفتح أي فترة جديدة في الأثناء: فليس عليه أبدًا إلا استحقاق واحد يؤدّيه، لا دَين يكبر. ويبقى الرابط قابلًا للأداء 14 يومًا بعد تاريخ الاستحقاق — أو بعد إصداره إن كان لاحقًا؛ فإن انتهت صلاحيته دون أداء، ينتقل الاشتراك إلى CANCELED ويصلكم subscription.canceled. وطريقة مواكبة هذه التأخيرات من جهة النشاط موصوفة في متابعة الاشتراكات غير المؤداة.
الخطوة 4: الاستماع إلى أحداث subscription.*
ثلاثة أحداث تتابع حياة الاشتراك:
| الحدث | المعنى | الإجراء المعتاد |
|---|---|---|
subscription.payment_succeeded | أُدّي استحقاق | تمديد الولوج، أو تجهيز الشحنة، أو الوسم بالمؤدّى |
subscription.payment_failed | فشلت محاولة أداء بالبطاقة على رابط استحقاق؛ ويبقى الرابط قابلًا للأداء | تسجيل الفشل، ودعوة الزبون إلى إعادة المحاولة على الرابط نفسه |
subscription.canceled | أُلغي الاشتراك لأن استحقاقًا بقي غير مؤدّى أكثر من 14 يومًا | قطع الخدمة وفق شروطكم |
صرّحوا بنقطة استقبال مشتركة صراحةً في هذه الأحداث الثلاثة:
curl -X POST 'https://api-psp.charipay.ma/api/v1/partner/webhooks/endpoints' \
-H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
-H 'Content-Type: application/json' \
-d '{
"url": "https://votre-boutique.ma/webhooks/charipay",
"description": "Subscriptions",
"enabledEvents": ["subscription.payment_succeeded", "subscription.payment_failed", "subscription.canceled"]
}'يحمل الرد signingSecret (whsec_…)، ولا يُعرض إلا مرة واحدة: احفظوه في خزنة. ومن جهة الاستقبال، وجّهوا حسب الترويسة Chari-Event-Type، وأزيلوا التكرار على Chari-Event-Id لا على Chari-Webhook-Id — فهذا الأخير يعرّف عملية التسليم لا الحدث.
وبالنسبة إلى الاشتراكات، يهمّ استثناء من القاعدة العامة: يحمل كل حدث subscription.* معرّف اشتراككم externalId (ExternalId)، وتاريخ الفترة المعنية (PeriodDate)، وmetadata الخاص بكم كما هو — في حين أن externalId الجلسة أو الرابط لا يعود. وإليكم مستقبِلًا أدنى، مع الدالة verify للتحقق من التوقيع:
app.post('/webhooks/charipay', express.raw({ type: '*/*' }), async (req, res) => {
const raw = req.body.toString('utf8');
if (!verify(raw, req.get('X-CHARI-SIGNATURE'), req.get('X-CHARI-TIMESTAMP'), secret)) {
return res.status(401).end();
}
const eventId = req.get('Chari-Event-Id');
if (await db.events.exists(eventId)) return res.status(200).end();
const type = req.get('Chari-Event-Type');
const event = JSON.parse(raw);
if (type === 'subscription.payment_succeeded') {
await members.markPaid(event.metadata.customerId); // your metadata, echoed verbatim
} else if (type === 'subscription.payment_failed') {
await members.noteFailedAttempt(event.metadata.customerId); // the link stays payable
} else if (type === 'subscription.canceled') {
await members.endAccess(event.metadata.customerId);
}
await db.events.insert({ eventId });
return res.status(200).end();
});وحين تلغون بأنفسكم، يحمل رد POST …/cancel الحالة CANCELED سلفًا: حدّثوا قاعدتكم في تلك اللحظة، دون انتظار أي حدث. وإن شككتم في حالة اشتراك، فأعيدوا قراءته عبر GET /v1/subscriptions/{reference}. والتوقيع والحماية من الإعادة ومحاولات التسليم الجديدة مفصّلة في إنجاح دمج الويب هوك.
تدبير دورة الحياة: الإيقاف والاستئناف والإلغاء والاستحقاقات
ما تتيحه بوابة التاجر على الاشتراك — الإيقاف المؤقت، والاستئناف، والإلغاء، واستعراض الاستحقاقات — متاح أيضًا عبر API. ومع نداء الإنشاء، هذه هي نقاط النهاية السبع للوحدة:
| النداء | الأثر |
|---|---|
GET /v1/subscriptions | يسرد اشتراكاتكم، صفحةً صفحة |
GET /v1/subscriptions/{reference} | يقرأ اشتراكًا، مع حالته ورابط الفترة الجارية (currentCharge) |
GET /v1/subscriptions/{reference}/charges | يسرد الاستحقاقات المُولَّدة — رابط لكل فترة، مع status وpayUrl —، الأحدث أولًا |
POST /v1/subscriptions/{reference}/pause | يعلّق الاشتراك: لا يُولَّد أي رابط جديد إلى حين الاستئناف |
POST /v1/subscriptions/{reference}/resume | يستأنف الدورة؛ ولا تُفوتَر الفترات التي مرّت أثناء الإيقاف بأثر رجعي |
POST /v1/subscriptions/{reference}/cancel | ينهي الاشتراك نهائيًا؛ ولا يُولَّد بعده أي استحقاق |
curl -X POST 'https://api-psp.charipay.ma/v1/subscriptions/sub_7Qa1bx/pause' \
-H 'X-CHARI-PAY-API-KEY: chari_sk_test_...'وتترتب على ذلك ثلاث قواعد تصميم. تغيير الصيغة هو cancel يليه POST /v1/subscriptions جديد للزبون نفسه. ولا احتساب نسبي ولا فترة تجريبية: يقوم الانطلاق المؤجَّل، عبر startDate، مقامها، ولا يُرسل أي رابط قبل تاريخ الاستحقاق الأول. وأخيرًا، GET …/charges هو مرجعكم في المطابقة: يظهر فيه كل استحقاق بحالته ورابطه، ما يتيح لكم أن تعيدوا إرسال رابط استحقاق ما زال مفتوحًا إلى زبون.
Idempotency والأخطاء المفيدة
في إنشاء الاشتراك، مفتاح الإعادة هو externalId: فريد لكل حساب ولكل بيئة، ويجعل إنشاءً ثانيًا بالقيمة نفسها يعيد الاشتراك الموجود بـ200 OK بدل 201 Created. وكلاهما نجاح: افحصوا رمز الحالة لا الجسم وحده. واشتقّوا externalId من كائنكم التجاري — معرّف زبونكم ورمز صيغتكم مثلًا — حتى لا تُنشئ إعادة شبكية أو إرسال مزدوج اشتراكين أبدًا. ولا يصرّح العقد بأي ترويسة Idempotency-Key لإنشاء الاشتراك: فـexternalId هو الذي يؤدّي هذا الدور.
وتتقاسم كل أخطاء /v1 الغلاف نفسه:
{
"error": {
"code": "VALIDATION_ERROR",
"message": "amount: must be greater than 0"
},
"correlationId": "b0c1e2d3-4f56-7890-abcd-ef0123456789"
}افحصوا code لا message أبدًا، وسجّلوا correlationId (فالـX-Request-Id الذي ترسلونه يصبح correlationId). والرموز التي ستصادفونها أكثر:
| الحالة | الرمز | السبب | ما العمل |
|---|---|---|---|
| 400 | VALIDATION_ERROR | حقل ناقص أو غير صالح (الدورية، التاريخ، قناة غير EMAIL، وصف يتجاوز 255 حرفًا) | صحّحوا الطلب، ولا تعيدوه كما هو |
| 401 | UNAUTHORIZED | مفتاح غائب أو غير صالح | تحقّقوا من الترويسة X-CHARI-PAY-API-KEY |
| 403 | PRODUCTION_ACCESS_NOT_ENABLED | مفتاح chari_sk_live_… قبل تفعيل الإنتاج | ابقوا في السندبوكس إلى حين التفعيل |
| 422 | WALLET_NOT_ACTIVE | طلب صالح، لكن المحفظة المعنية غير نشطة | لا تعيدوا الطلب في حلقة؛ تواصلوا مع الفريق مع إرفاق correlationId |
| 429 | RATE_LIMITED | طلبات كثيرة جدًا | انتظروا Retry-After ثم أعيدوا |
وأخطاء 5xx من جهتنا: أعيدوا الطلب بمفتاح Idempotency الخاص بكم — وفي إنشاء الاشتراك، بـexternalId نفسه.
اختبار الاستحقاقات في السندبوكس
انتظار شهر كامل للتحقق من استحقاق ثانٍ ليس خطة اختبار. والطريقة تقوم على ثلاثة إعدادات، دون أي نداء خاص: startDate بتاريخ اليوم، كي يُنشأ الرابط الأول فورًا؛ وبطاقة الاختبار، لأدائه؛ والدورية DAILY، كي يصل استحقاق ثانٍ منذ اليوم الموالي.
curl -X POST 'https://api-psp.charipay.ma/v1/subscriptions' \
-H 'X-CHARI-PAY-API-KEY: chari_sk_test_...' \
-H 'Content-Type: application/json' \
-d '{
"clientId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"amount": 10.00,
"description": "Test plan - daily",
"frequency": "DAILY",
"startDate": "2026-10-05",
"channels": ["EMAIL"],
"externalId": "test-sub-001"
}'ضعوا تاريخ اليوم مكان startDate، على توقيت Africa/Casablanca. يحمل الرد الرابط الأول في currentCharge: افتحوا payUrl الخاص به وادفعوا ببطاقة الاختبار — 4918 9141 0719 5005، وCVV 123، وأي تاريخ انتهاء مستقبلي، ورمز 3-D Secure 555. ينتقل الاشتراك إلى ACTIVE، ويصل subscription.payment_succeeded إلى نقطة الاستقبال الخاصة بالسندبوكس. وفي اليوم الموالي، يُفتح الاستحقاق الثاني: يحمل currentCharge رابطًا جديدًا، ويسرد GET …/charges استحقاقين. وتُرسل أحداث الويب هوك كما في الإنتاج.
وتتسع خطة اختبار كاملة لثماني خطوات، على ثلاثة أيام:
- 1أنشئوا الزبون، ثم اشتراكًا بدورية
DAILYوstartDateبتاريخ اليوم: الحالةINCOMPLETE، وcurrentChargeحاضر معpayUrlالخاص به. - 2افتحوا
payUrlوادفعوا ببطاقة الاختبار، رمز 3-D Secure 555: الحالةACTIVE، وactivatedAtمحدَّد، والحدثsubscription.payment_succeededمُستلَم. - 3في اليوم الموالي، أعيدوا قراءة الاشتراك: فُتح
currentChargeجديد وتقدّمnextRunDate. أدّوا هذا الرابط الثاني: يصل حدث جديد. - 4في اليوم الذي يليه، اتركوا الاستحقاق الثالث دون أداء: لا تُفتح أي فترة جديدة، ويجب أن تُظهره قاعدة بياناتكم في الانتظار.
- 5تحقّقوا من أن قاعدة بياناتكم محدَّثة وأن الحدث المستلَم مرتين لا يُعالَج إلا مرة واحدة.
- 6أوقفوا مؤقتًا ثم استأنفوا: الحالتان
PAUSEDثمACTIVE، دون أي رابط مُولَّد أثناء الإيقاف. - 7ألغوا: يحمل الرد الحالة
CANCELED، وتعكسها قاعدة بياناتكم. - 8اسردوا الاستحقاقات (
GET …/charges) وطابقوها مع قاعدة بياناتكم.
ولا يتطلب الانتظار إلا الانتقال إلى CANCELED بعد 14 يومًا دون أداء: اتركوا اشتراك اختبار دون أداء، وتحقّقوا من معالجتكم لـsubscription.canceled بعد أسبوعين. أما بقية الاختبار — البطاقة، وسيناريوهات الأداء، وما لا يُختبر — ففي اختبار الدفع في وضع الاختبار.
أسئلة شائعة
ما الحقول الإلزامية لإنشاء اشتراك عبر API؟
ستة حقول: clientId (UUID زبون موجود)، وamount بالدرهم، وdescription، وfrequency (DAILY أو WEEKLY أو MONTHLY أو YEARLY)، وstartDate بصيغة YYYY-MM-DD، وchannels وقيمته ["EMAIL"]. ويجب فوق ذلك أن يكون للزبون بريد إلكتروني صالح، لأن رابط الدفع الخاص بكل استحقاق يُرسل إليه. وثلاثة حقول اختيارية: endDate وexternalId وmetadata.
لماذا يبقى اشتراكي في الحالة INCOMPLETE؟
لأن استحقاقه الأول لم يُؤدَّ بعد. يبقى الاشتراك INCOMPLETE ما دام زبونكم لم يؤدِّ رابط الدفع الأول، في الصفحة المستضافة، بالبطاقة مع 3-D Secure. اقرؤوه عبر GET /v1/subscriptions/{reference}: يحمل currentCharge الاستحقاق المفتوح وpayUrl الخاص به، ويمكنكم إعادة إرساله إلى زبونكم؛ وإن كان تاريخ الاستحقاق الأول مستقبليًا، فلم يُنشأ أي رابط بعد.
هل البريد الإلكتروني للزبون إلزامي للاشتراك؟
نعم، عمليًا. لا يشترط مخطط الزبون إلا name، لكن رابط الدفع الخاص بكل استحقاق والتذكيرات تُرسل بالبريد الإلكتروني: فدون عنوان صالح، لن يتلقى زبونكم شيئًا. املؤوا إذن email منذ POST /v1/clients، أو أكملوه لاحقًا عبر PUT /v1/clients/{id}، قبل إنشاء الاشتراك.
ماذا يحدث إن لم يؤدِّ زبوني استحقاقًا؟
يتلقى تذكيرًا بالبريد الإلكتروني كل يوم، بالرابط نفسه، ولا تُفتح أي فترة جديدة ما دام الاستحقاق غير مؤدّى. ويبقى الرابط قابلًا للأداء 14 يومًا بعد تاريخ الاستحقاق؛ فإن انتهت صلاحيته دون أداء، ينتقل الاشتراك إلى CANCELED ويصلكم subscription.canceled. أما محاولة الأداء بالبطاقة المرفوضة على الرابط فتصلكم في subscription.payment_failed، ويبقى الرابط قابلًا للأداء.
هل يعود externalId الخاص بي في أحداث الاشتراك؟
نعم. إنه استثناء من القاعدة العامة: externalId الجلسة أو الرابط لا يعود في الأحداث، لكن externalId الاشتراك يعود في كل حدث subscription.*، مع تاريخ الفترة (PeriodDate) وmetadata الخاص بكم كما هو. ويمكنكم إذن ربط كل استحقاق بملف زبونكم دون جدول مطابقة إضافي، شرط أن تشتقّوا externalId من معرّف ثابت في نظامكم.
ماذا يحدث إن أعدت الإنشاء بـexternalId نفسه؟
لا تُنشئ API نسخة مكررة: بل تعيد الاشتراك الموجود بالحالة 200 OK بدل 201 Created. عاملوا الحالتين كنجاح واقرؤوا reference المُعاد. وexternalId فريد لكل حساب ولكل بيئة: يمكن أن توجد القيمة نفسها مرة في السندبوكس ومرة في الإنتاج، دون أي تعارض بين البيئتين.
ما الدوريات التي تقبلها API الاشتراكات؟
أربع قيم لـfrequency: DAILY وWEEKLY وMONTHLY وYEARLY. والمبلغ ثابت طوال حياة الاشتراك؛ ولتغيير الصيغة أو الدورية، ألغوا الاشتراك وأنشئوا اشتراكًا جديدًا للزبون نفسه. ويحدّ تاريخ انتهاء اختياري (endDate) المدة، فيبلغ الاشتراك الحالة COMPLETED متى حلّ ذلك التاريخ وأُدّي الاستحقاق الأخير.
كيف أختبر الاستحقاقات الموالية دون انتظار؟
أنشئوا في السندبوكس اشتراكًا بدورية DAILY وstartDate بتاريخ اليوم: يُنشأ الرابط الأول فورًا ويُعاد في currentCharge. أدّوه ببطاقة الاختبار، رمز 3-D Secure 555: ينتقل الاشتراك إلى ACTIVE ويصل subscription.payment_succeeded. وفي اليوم الموالي، يُفتح استحقاق ثانٍ، برابط جديد يُؤدّى بالطريقة نفسها.
الخطوة التالية
نفّذوا الخطوات الأربع في السندبوكس باشتراك DAILY ينطلق في اليوم نفسه، وأدّوا استحقاقين ببطاقة الاختبار، وتحقّقوا من أحداث الويب هوك: ابدؤوا في وضع الاختبار. وحين تنجح خطة اختباركم، حضّروا الانتقال بقراءة الانتقال من السندبوكس إلى الإنتاج: لا يتغيّر سوى المفتاح وسرّ الويب هوك.
بقلم فريق ChariPay.