دليل REST API الكامل لربط التحقق من المدفوعات في إيصالات بخادمك. أنشئ طلبات الدفع، وأرفق مرجع المحفظة من المشتري، واحصل على التحقق لحظياً عبر Webhooks.
https://api.esaalat.com/api/v1/merchantPOST /token · GET /wallets/ · POST /intents/ · GET/PATCH /intents/{id}/
واجهة Merchant REST API هي الطريقة التي يربط بها خادمك خدمة إيصالات. تنشئ طلب دفع بالمبلغ المحدد وبالمحفظة التي تريد التحصيل إليها. عندما يدفع المشتري، تظهر له المحفظة مرجع العملية. ترفق هذا المرجع بالطلب، فتتحقق إيصالات من الدفعة وتُشعرك عبر Webhook موقّع.
| الطريقة | المسار |
|---|---|
| POST | /token |
| GET | /wallets/ |
| POST | /intents/ |
| GET | /intents/ |
| GET | /intents/{id}/ |
| PATCH | /intents/{id}/ |
صادق باستخدام بيانات اعتماد عميلك للحصول على رمز JWT قصير الأجل. تُنشأ بيانات الاعتماد من لوحة التحكم ← مفاتيح API.
/api/v1/merchant/token| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
client_id | نص | مطلوب | معرّف عام يمكن تضمينه بأمان في تطبيقك. |
client_secret | نص | مطلوب | يُعرض مرة واحدة فقط عند الإنشاء ولا يمكن استرجاعه لاحقاً. جدّد المفتاح من لوحة التحكم إذا تسرب. |
curl -sS -X POST https://api.esaalat.com/api/v1/merchant/token \
-H "ESAALAT-CLIENT-ID: <client_id>" \
-H "ESAALAT-CLIENT-SECRET: <client_secret>"قبل إنشاء طلب، احصل على قائمة المحافظ التي يمكنك التحصيل إليها. تُعاد المحافظ التي المراقبة مفعّلة فيها فقط. محفظة الاختبار مستثناة إلا إذا طلبتها عبر ?include_test=1.
/api/v1/merchant/wallets/| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
id | UUID | اختياري | معرّف المحفظة. مرّره كقيمة wallet عند إنشاء الطلب. |
name / account_number | نص | اختياري | الاسم الذي يراه المشتري، ورقم الحساب الذي يحوّل إليه المال. |
sender_name | نص | اختياري | معرّف المرسل الذي تصل منه تنبيهات مدفوعات هذه المحفظة. |
currency | نص | اختياري | عملة المحفظة (ريال YER حالياً). |
provider | كائن | اختياري | بيانات مزوّد المحفظة: الاسم المعروض واللون ورابط الشعار. |
is_test | منطقي | اختياري | true لمحفظة الاختبار المخصصة لحسابك (تُعاد فقط مع ?include_test=1). |
curl -sS https://api.esaalat.com/api/v1/merchant/wallets/ \
-H "Authorization: Bearer <access_token>"/api/v1/merchant/intents/| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
wallet | UUID | مطلوب | محفظة من حسابك مفعّلة فيها المراقبة. المحافظ التي المراقبة مفعّلة فيها فقط هي التي تستقبل المدفوعات. |
amount | قيمة عشرية | اختياري | إجمالي المبلغ المطلوب تحصيله، مثل "1234.56". مطلوب إذا لم تُرسل items. |
items | مصفوفة عناصر | اختياري | بنود الطلب، ويُحتسب الإجمالي منها. مطلوبة إذا لم يُرسل amount. وإذا أُرسل كلاهما فسيُتجاهل amount. |
currency | نص | اختياري | يدعم ريال YER فقط. يُفترض عملة المحفظة ويجب أن تطابقها. |
external_order_id | نص حتى 128 حرفاً | اختياري | مرجع طلبك الخاص، ويُعاد في الاستجابات وWebhooks. |
notes | نص حتى 500 حرف | اختياري | ملاحظة حرة تُحفظ مع الطلب. |
curl -sS -X POST https://api.esaalat.com/api/v1/merchant/intents/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-H "ESAALAT-IDEMPOTENCY-KEY: a1b2c3d4-0000-4000-8000-000000000001" \
-d '{
"wallet": "b48249d2-9b34-4414-b20e-ffd8dfedaf89",
"amount": "1234.56",
"currency": "YER",
"external_order_id": "order-12345",
"notes": "Optional note to the merchant"
}'{
"wallet": "b48249d2-9b34-4414-b20e-ffd8dfedaf89",
"amount": "1234.56",
"currency": "YER",
"external_order_id": "order-12345",
"notes": "Optional note to the merchant"
}{
"name": "Product name", // required, ≤100 chars
"description": "Optional", // ≤500 chars
"price": "1500.00", // decimal string, required
"quantity": 1 // integer ≥ 1, default 1
}/api/v1/merchant/intents/{id}/| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
reference | نص حتى 128 حرفاً | مطلوب | مرجع عملية المحفظة، مع إزالة المسافات البيضاء. |
curl -sS -X PATCH https://api.esaalat.com/api/v1/merchant/intents/<intent_id>/ \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{"reference": "12345678"}'{
"reference": "12345678"
}اعرض طلباتك من الأحدث إلى الأقدم، ومقيدة دائماً بحسابك. 20 طلباً في الصفحة افتراضياً؛ ويمكن التحكم بالترقيم عبر ?page_size= (الحد الأقصى 100) و ?page=.
/api/v1/merchant/intents/| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
status | قائمة مفصولة بفواصل | اختياري | PENDING, VERIFIED, EXPIRED, CANCELLED, WRONG_AMOUNT. مثال: ?status=VERIFIED,WRONG_AMOUNT. قيمة غير صالحة → 400. |
code | نص | اختياري | رقم الدفع بالضبط، مثال: ?code=P7K4X92 |
reference | نص | اختياري | مرجع المحفظة بالضبط، مثال: ?reference=12345678 |
external_order_id | نص | اختياري | مرجع طلبك الخاص (مطابقة تامة). |
wallet | UUID | اختياري | تقييد النتائج بمحفظة واحدة. |
created_after | ISO 8601 | اختياري | يشمل التواريخ من هذه اللحظة (>=). |
created_before | ISO 8601 | اختياري | يشمل التواريخ حتى هذه اللحظة (<=). |
search | نص | اختياري | نص حر يطابق reference أو code أو external_order_id. |
ordering | نص | اختياري | created_at, verified_at, payable_amount, status. أضف - للعكس. |
curl -sS "https://api.esaalat.com/api/v1/merchant/intents/?status=VERIFIED&created_after=2026-09-09T00:00:00Z&page_size=100" \
-H "Authorization: Bearer <access_token>"احصل على الحالة الحالية وتفاصيل طلب واحد. أي طلب من حساب آخر يعيد 404.
/api/v1/merchant/intents/{id}/| الاسم | النوع | مطلوب | الوصف |
|---|---|---|---|
status | نص | اختياري | مصدر الحقيقة لديك: إحدى الحالات المذكورة أدناه. |
paid_amount | قيمة عشرية | اختياري | يُعيّن فقط عندما تكون الحالة WRONG_AMOUNT، ويوضّح المبلغ الذي أرسله المشتري فعلياً. |
matched_event | كائن | اختياري | حدث الدفع المطابق الذي أكّد الطلب (مرجعه ومبلغه ومرسله). |
device | كائن | اختياري | الجهاز الذي أبلغ عن الدفعة. يبقى المعرّف ثابتاً حتى عند تجديد رمز الجهاز. |
manual_override / collected_manually | منطقي | اختياري | true عندما يحصّل التاجر الدفعة يدوياً من قائمة غير المطابقة. |
curl -sS https://api.esaalat.com/api/v1/merchant/intents/<intent_id>/ \
-H "Authorization: Bearer <access_token>"{
"id": "dd157a06-a065-475d-8723-d98a61698aa0",
"code": "P7K4X92",
"external_order_id": "order-12345",
"reference": "12345678",
"status": "VERIFIED",
"base_amount": "1234.56",
"payable_amount": "1234.56",
"paid_amount": null,
"currency": "YER",
"items": [
{
"name": "Product name",
"description": "",
"price": "1234.56",
"quantity": 1,
"total_price": "1234.56"
}
],
"notes": "",
"wallet": {
"id": "b48249d2-9b34-4414-b20e-ffd8dfedaf89",
"name": "Kuraimi - Main",
"sender_name": "777777777",
"is_test": false,
"sim_slot": "SIM 1",
"account_number": "777777777"
},
"provider": {
"id": "3f0a4b1e-0000-4000-8000-000000000002",
"name": "KURAIMI",
"display_name": "Kuraimi",
"theme_color": "#0b8f4c",
"logo_url": "https://<cdn>/kuraimi_256.png",
"provider_status": "ACTIVE"
},
"expires_at": "2026-09-09T14:30:00+03:00",
"created_at": "2026-09-09T13:30:00.123456+03:00",
"verified_at": "2026-09-09T13:41:22.654321+03:00",
"manual_override": false,
"collected_manually": false,
"matched_event": {
"id": "32fd9972-71fd-4b87-82ce-501061ab7c5d",
"amount": "1234.56",
"sender": "777777777",
"reference": "12345678",
"created_at": "2026-09-09T13:41:21+03:00"
},
"device": {
"id": "5a1f6c3d-0000-4000-8000-000000000004",
"name": "Shop phone 1"
},
"subscription": null
}| الاسم | الوصف | نهائية |
|---|---|---|
PENDING | أُنشئ الطلب بانتظار دفعة المشتري والمرجع. | — |
VERIFIED | تم اكتشاف الدفعة ومطابقتها (المحفظة + المرجع + المبلغ بالضبط). | نهائية |
WRONG_AMOUNT | طابق المرجع لكن المبلغ المدفوع يختلف عن المبلغ المطلوب. يسجّل paid_amount ما وصل، ولا يُؤكد الطلب تلقائياً، فعلى المشتري التواصل معك. | نهائية |
EXPIRED | انتهت مهلة الساعة دون تحقق. | نهائية |
CANCELLED | أُلغي من قبل التاجر (لوحة التحكم). | نهائية |
تُعد Webhooks القناة الأساسية للتحقق؛ استخدم نقاط العرض والاسترجاع للمراجعة اللاحقة. اضبط نقاط النهاية من لوحة التحكم ← Webhooks، ويمكن تقييدها بمحفظة معينة.
يحمل كل طلب ترويسة X-Esaalat-Signature بالصيغة t=<unix-ts>,v1=<hex>. قيمة v1 هي HMAC-SHA256 لـ "{ts}.{raw_body}" باستخدام سر نقطة النهاية لديك. قارن دائماً بـ hmac.compare_digest، ويمكنك رفض الطلبات الأقدم من ~5 دقائق كحماية من إعادة التشغيل.
import hashlib, hmac
def verify_signature(secret: str, body: bytes, signature: str) -> bool:
ts, v1 = (p.split("=", 1)[1] for p in signature.split(","))
digest = hmac.new(
secret.encode(), f"{ts}.{body.decode()}".encode(), hashlib.sha256
).hexdigest()
return hmac.compare_digest(digest, v1)الحدث الرئيسي: تم التحقق من الدفعة، تلقائياً أو يدوياً.
{
"event": "payment.verified",
"payment_id": "P7K4X92",
"intent_id": "dd157a06-a065-475d-8723-d98a61698aa0",
"order_id": "order-12345",
"reference": "12345678",
"base_amount": "1234.56",
"amount": "1234.56",
"currency": "YER",
"status": "VERIFIED",
"verified_at": "2026-09-09T13:41:22+03:00",
"manual_override": false
}وصل مبلغ إلى محفظة حقيقية دون أن يطالب به أي طلب. يُرسل فقط إذا فعّلت النقطة الخيار صراحةً. لا يُطلق أبداً لمحفظة الاختبار.
{
"event": "payment.unmatched",
"event_id": "32fd9972-71fd-4b87-82ce-501061ab7c5d",
"reference": "12345678",
"amount": "1234.56",
"currency": "YER",
"wallet": "Kuraimi - Main",
"received_at": "2026-09-09T13:41:21+03:00",
"is_test": false
}يُطلق عند أي دفعة تصل إلى محفظة الاختبار، حتى بدون إنشاء طلب. يتيح لك اختبار التكامل بالكامل عبر محفظة الاختبار.
{
"event": "payment.received",
"event_id": "32fd9972-71fd-4b87-82ce-501061ab7c5d",
"reference": "12345678",
"amount": "1234.56",
"currency": "YER",
"resolution": "UNMATCHED",
"received_at": "2026-09-09T13:41:21+03:00",
"is_test": true
}تُقيَّد الطلبات لكل بيانات اعتماد على حدة. عند تجاوز الحد تستلم 429 مع ترويسة Retry-After. تعامل معها بسلاسة.
| المسار | الحد اللحظي | الحد اليومي |
|---|---|---|
POST /token | 10/دقيقة | 500/يوم |
POST /intents/, GET/PATCH /intents/{id}/ | 240/دقيقة (~4 طلبات/ثانية) | 50,000/يوم |
GET /intents/ (قائمة) | 60/دقيقة | 50,000/يوم |
يتبع كل خطأ صيغة موحّدة:
{
"type": "validation_error",
"errors": [
{ "code": "required", "detail": "This field is required.", "attr": "wallet" }
]
}| الاسم | الوصف |
|---|---|
400 | محتوى غير صالح، محفظة غير معروفة، عامل تصفية غير صحيح، مراقبة غير مفعّلة في المحفظة، مرجع على طلب غير معلّق، أو تجاوز الحصة. |
401 | رمز Bearer مفقود أو غير صالح أو منتهي. |
403 | استخدام رمز لوحة التحكم (مستخدم) على نقاط التاجر. يلزم رمز بيانات الاعتماد. |
404 | معرّف طلب غير معروف (أو طلب من حساب آخر). |
429 | تم تجاوز حد الطلبات. احترم ترويسة Retry-After. |
500 | حدث خطأ داخلي. أبلغنا عنه. |