تخطي للذهاب إلى المحتوى

التوثيق — الإصدار v1

المصادقة

كل نداء يحمل ثلاث ترويسات. التوقيع على "{timestamp}.{raw_body}" بخوارزمية HMAC-SHA256 وسرّك، ونافذة القبول ٣٠٠ ثانية — فاضبط ساعة خادمك، فهي أكثر أسباب فشل التوقيع.

X-Syriana-Key:       sy_live_xxxxxxxxxxxx
X-Syriana-Timestamp: 1756000000
X-Syriana-Signature: hex(hmac_sha256(secret, "1756000000." + body))
مثال بايثون كامل
import hashlib, hmac, json, time, requests

KEY, SECRET = "sy_test_...", "...."
BASE = "https://syriana.store"

def call(method, path, payload=None):
    body = json.dumps(payload, ensure_ascii=False) if payload else ""
    ts = str(int(time.time()))
    sig = hmac.new(SECRET.encode(), f"{ts}.{body}".encode(),
                   hashlib.sha256).hexdigest()
    return requests.request(method, BASE + path, data=body.encode(), headers={
        "X-Syriana-Key": KEY,
        "X-Syriana-Timestamp": ts,
        "X-Syriana-Signature": sig,
        "Content-Type": "application/json",
    })

print(call("GET", "/api/v1/ping").json())

شكل الردّ

ثابت لا يتغيّر: النجاح دائماً data وmeta، والفشل دائماً error. الحقول تُضاف ولا تُحذف، فما تبنيه اليوم يبقى يعمل.

{"data": {...}, "meta": {"version": "v1", "page": 1, "total": 201}}
{"error": {"code": "missing_scope", "message": "..."}}

نقاط النهاية

التحقّق

GET /api/v1/ping توقيع فقط
هل مفتاحي وتوقيعي صحيحان؟
أوّل نداء يجب أن تجرّبه. يعيد وقت الخادم — قارنه بوقتك، فاختلاف الساعة أكثر سبب لفشل التوقيع.
يعيد: {"ok": true, "time": "...", "sandbox": true}
GET /api/v1/me توقيع فقط
من أنا وما صلاحياتي
إن جاءك 403 من نقطة أخرى، فهذه تخبرك أي صلاحية ينقصك قبل أن تسأل الدعم.
يعيد: {"app": "...", "scopes": [...], "wallet": {...}}

الكتالوج

GET /api/v1/products catalog:read
المنتجات المنشورة بسعر التاجر
معاملات: page · page_size (حتى ٢٠٠) · search · audience (individual/business/enterprise/mixed).
يعيد: قائمة منتجات، كلٌّ برمز sku ثابت وسعرك أنت.
GET /api/v1/products/{sku} catalog:read
تفاصيل منتج واحد
يقبل SY-123 أو 123. يضيف الوصف والسمات وتاريخ آخر تعديل.
يعيد: كائن منتج مفصّل.
GET /api/v1/products/changes catalog:read
ما تغيّر فقط منذ وقت معيّن
المعامل since إلزامي بصيغة ISO. يشمل ما أُلغي نشره عمداً — يجب أن تعرف متى تتوقّف عن البيع، لا متى تبدأ فقط.
يعيد: قائمة منتجات مفصّلة مرتّبة بتاريخ التعديل.

المحفظة

GET /api/v1/wallet wallet:read
الرصيد والشروط
الحقل spendable هو ما تستطيع إنفاقه فعلاً الآن — لا تحسبه بنفسك من الرصيد والسقف.
يعيد: {"balance": .., "spendable": .., "mode": "prepaid"}
GET /api/v1/wallet/entries wallet:read
دفتر الحركات
كل شحن وخصم واسترداد بترتيب زمني عكسي. أساس أي مطابقة.
يعيد: قائمة حركات بالرصيد بعد كلٍّ منها.
GET /api/v1/wallet/topup-methods wallet:read
وسائل الشحن المتاحة لك
تختلف من تاجر لآخر. max_topup_now هو أكبر شحنة لن يرفضها سقف الرصيد.
يعيد: قائمة وسائل بحدودها.
POST /api/v1/wallet/topup wallet:write
افتح شحنة واحصل على رابط دفعها
الجسم: {"amount": 50, "provider": "fawaterk"}. الحدّ الأدنى ٥ دولار، والأقصى ما يبقى تحت سقف رصيدك. لا نستقبل أي بيانات بطاقة — تُدفع على صفحة المتجر نفسها.
يعيد: 201 مع pay_url — افتحه في المتصفّح لإتمام الدفع.
GET /api/v1/wallet/topups wallet:read
شحناتك وحالتها
شحنة بحالة draft لم تُدفع بعد؛ تُلغى تلقائياً بعد ٤٨ ساعة.
يعيد: قائمة شحنات.

الطلبات

POST /api/v1/orders orders:write
اشترِ تراخيص
ترويسة Idempotency-Key إلزامية. الجسم: {"items": [{"sku": "SY-123", "quantity": 2}], "reference": "رقمك"}. يُخصم الرصيد ثم تُصدر التراخيص في معاملة واحدة: إمّا الاثنان أو لا شيء.
يعيد: 201 مع order_id والتراخيص، أو 402 لعدم كفاية الرصيد، أو 409 لتضارب مفتاح التكرار.
GET /api/v1/orders orders:read
طلباتك عبر الواجهة
مقسّمة صفحات، الأحدث أولاً.
يعيد: قائمة طلبات مختصرة.
GET /api/v1/orders/{order_id} orders:read
تفاصيل طلب
طلب لا يخصّك يعيد 404 لا 403 — حتى لا يصير الردّ نفسه وسيلة لاستكشاف طلبات غيرك.
يعيد: الطلب بأصنافه وتراخيصه.
GET /api/v1/orders/{order_id}/licenses licenses:read
مفاتيح طلب
ترخيص حالته pending لا مفتاح له بعد (منتج يُجهَّز يدوياً أو مخزون مفاتيح فارغ). يحمل عندئذٍ available_by (الموعد الأقصى) و availability_note (النصّ الذي نقوله لعملائنا أنفسنا) — اعرضهما لعميلك. ويصلك إشعار license.delivered لحظة توفّره. العدد المتبقّي في meta.pending.
يعيد: قائمة تراخيص بحالة كلٍّ منها.

الإشعارات الصادرة

نرسلها إلى الرابط الذي تسجّله، موقّعة بنفس الخوارزمية في X-Syriana-Signature. أعد 2xx لتأكيد الاستلام؛ وإلّا نعيد المحاولة ست مرّات على مدى ٤ ساعات.

order.fulfilled اكتمل الطلب وصدرت تراخيصه فعلاً (مفاتيح حقيقية).
order.processing قُبل الطلب وخُصم، وبعض التراخيص قيد التجهيز.
order.cancelled أُلغي الطلب وأُعيد المبلغ إلى رصيدك.
license.delivered وصل مفتاح كان طلباً مسبقاً — اقرأه من /orders/{id}/licenses.
wallet.low الرصيد قارب النفاد — قبل أن يفشل طلب، لا بعده.
wallet.topped_up وصلت شحنتك وأُضيفت إلى رصيدك.
wallet.settled صدرت فاتورة دورتك الآجلة وصُفِّر الرصيد.

رموز الأخطاء

الرمزHTTPالمعنى
unauthorized 401 مفتاح أو توقيع غير صالح. لا نفرّق بين السببين عمداً.
stale_timestamp 401 ساعة خادمك بعيدة أكثر من ٥ دقائق عن ساعتنا.
app_not_live 403 التطبيق لم يُعتمد بعد؛ يعمل تجريبياً فقط.
app_suspended 403 التطبيق موقوف.
missing_scope 403 المفتاح لا يملك الصلاحية المطلوبة لهذه النقطة.
no_wallet 403 مفتاح قراءة بلا محفظة — البيع يحتاج محفظة.
not_found 404 لا يوجد مورد بهذا المعرّف يخصّك.
invalid_request 400 جسم الطلب ناقص أو خارج الحدود المسموحة.
invalid_json 400 الجسم ليس كائن JSON صالحاً.
unknown_sku 400 رمز منتج غير معروف أو غير قابل للبيع.
missing_parameter 400 معامل إلزامي غائب (مثل since).
invalid_parameter 400 قيمة معامل غير مفهومة.
currency_mismatch 409 محفظتك بعملة غير عملة الكتالوج.
idempotency_required 400 ترويسة Idempotency-Key ناقصة على الطلبات.
idempotency_conflict 409 نفس المفتاح استُخدم بجسم مختلف.
request_in_progress 409 نسخة سابقة من نفس الطلب قيد المعالجة.
wallet_busy 409 طلب آخر يستخدم محفظتك الآن — أعد المحاولة.
conflict_retry 409 تعارض مؤقّت مع طلب متزامن. أعد المحاولة بنفس مفتاح التكرار.
insufficient_funds 402 الرصيد لا يكفي.
topup_refused 400 الشحنة تحت الحدّ الأدنى أو فوق السقف أو بوسيلة غير متاحة لك — الرسالة تقول أيّها.
rate_limited 429 تجاوزت حدّ الطلبات في الدقيقة.
payload_too_large 413 حجم الطلب أكبر من المسموح.
internal_error 500 خطأ لدينا. سُجّل بالكامل للمراجعة.