الواجهة البرمجية والتكامل

ينشئ نظام نقاط البيع أو ERP أو متجرك الإلكتروني التذاكر، ويغيّر حالتها، ويتلقى كل مرحلة عبر webhook. ويتلقى الزبائن الإشعارات نفسها كما من التطبيق.

متاحة عند الطلب خلال فترة الإطلاق: راسلنا ونفعّل واجهة API لمحلّك.

BASEhttps://api.tfa9adni.com/v1

البداية

كل الطلبات تُرسل إلى هذا العنوان، عبر HTTPS، وبصيغة JSON في الاتجاهين.

لكل ردّ الغلاف نفسه: success و data، أو success بقيمة false مع error فيه رمز. المبالغ بالوحدات الصغرى (المليم، السنتيم) مع العملة وعدد الأرقام العشرية. التواريخ بصيغة ISO 8601 وبتوقيت UTC.

GET/v1/shop

اختبار الاتصال

يعيد المحل المرتبط بالمفتاح وعملته ومنطقته الزمنية وصلاحيات المفتاح.

أنشئ مفتاحًا في التطبيق: المحل › واجهة API. صاحب المحل وحده يستطيع ذلك. ثم جرّب الاتصال:

المصادقة

أرسل المفتاح في ترويسة Authorization. المفتاح لا يصل إلا إلى محله.

يظهر المفتاح مرة واحدة عند إنشائه. احفظه في خادمك أو في برنامج الصندوق، ولا تضعه في صفحة ويب أو في رسالة. المفتاح الملغى يتوقف عن العمل خلال دقيقة. خمسة مفاتيح فعّالة على الأكثر لكل محل.

صلاحيات المفتاح

  • tickets:readقراءة التذاكر.
  • tickets:writeإنشاء التذاكر وتغيير حالتها.
  • clients:readإيجاد زبون وقراءة بطاقة الوفاء.
  • loyalty:writeإضافة أختام واستعمال مكافأة.

« وصول كامل » يمنح الصلاحيات الأربع، و« قراءة فقط » يمنح tickets:read و clients:read.

التذاكر

حالات التذكرة

  • workshopفي الورشة، قيد العمل.
  • readyجاهزة، في انتظار الزبون.
  • impossibleتعذّر الإصلاح، والغرض في انتظار صاحبه.
  • collectedاستُلمت. يبيّن outcome هل كانت جاهزة أم تعذّر إصلاحها.
  • abandonedمغلقة: لم تُستلم أبدًا، أو دون أخبار من المحل طوال 60 يومًا. يوضّح abandon_reason السبب (uncollected أو no_news).

POST/v1/tickets

إنشاء تذكرة

ينشئ تذكرة في الورشة. رقمها يتبع أرقام التطبيق.

ترويسة Idempotency-Key إلزامية: إذا انقطعت الشبكة، أعد إرسال الطلب نفسه بالمفتاح نفسه فتصلك التذكرة نفسها مع replayed بقيمة true، ولا تُنشأ نسخة ثانية. الأرقام تتبع أرقام التطبيق.

الترويسات

  • Idempotency-Key string إلزامي

    مفتاح فريد لكل محاولة: إعادة الطلب نفسه تعيد التذكرة نفسها.

محتوى JSON

  • service string إلزامي

    الخدمة، كما في التطبيق.

  • type string اختياري

    repair للإصلاح أو prepare للطلبية. القيمة الافتراضية repair.

  • item string اختياري

    الغرض المودَع.

  • description string اختياري

    ملاحظة للورشة.

  • items array اختياري

    عدة أغراض (من 2 إلى 20): label و service و price_minor.

  • client_id uuid اختياري

    زبون يعرف المحل من قبل.

  • client_phone string اختياري

    رقم الزبون: تُعرض عليه التذكرة.

  • price_minor integer اختياري

    السعر بالوحدات الصغرى.

  • deposit_minor integer اختياري

    العربون بالوحدات الصغرى.

  • promised_at datetime اختياري

    اليوم الموعود، بصيغة ISO 8601.

  • external_ref string اختياري

    مرجعك الخاص، 64 حرفًا على الأكثر.

client_phone لا يربط أحدًا: تُعرض التذكرة على الحساب الذي يحمل هذا الرقم، فيقبلها أو يحظر المحل. الرد واحد سواء وُجد حساب أم لا.

GET/v1/tickets

عرض التذاكر

تصفية تذاكر المحل وتقسيمها إلى صفحات ومزامنتها.

المرشحات: state (عدة قيم مفصولة بفواصل)، number، client_id، phone، external_ref، created_after، created_before، updated_since. قيمة limit من 1 إلى 100 (50 افتراضيًا). إذا كانت has_more صحيحة، أعد next_cursor في cursor. مع updated_since يتبع الترتيب وقت التحديث، وهذا مفيد للمزامنة.

معاملات الرابط

  • state string اختياري

    حالة أو أكثر، مفصولة بفواصل.

  • number integer اختياري

    رقم التذكرة.

  • phone string اختياري

    الرقم المكتوب على التذكرة.

  • external_ref string اختياري

    مرجعك.

  • updated_since datetime اختياري

    ما تغيّر منذ هذا التاريخ فقط.

  • limit integer اختياري

    من 1 إلى 100، و50 افتراضيًا.

  • cursor string اختياري

    قيمة next_cursor من الصفحة السابقة.

GET/v1/tickets/{id}

قراءة تذكرة

تذكرة واحدة بمعرّفها. تذكرة محل آخر تعيد 404.

GET/v1/tickets/by-number/{n}

البحث بالرقم

أحدث تذكرة مفتوحة تحمل هذا الرقم.

تعود الأرقام إلى 1 بعد 9999: يعيد by-number أحدث تذكرة مفتوحة، وإلا الأحدث، ويذكر meta.others البقية.

POST/v1/tickets/{id}/status

تغيير الحالة

جاهز أو تعذّر أو العودة إلى الورشة أو تم الاستلام.

القواعد نفسها كما في التطبيق: جاهزة أو تعذّر الإصلاح من الورشة، مستلمة من جاهزة أو تعذّر الإصلاح، والعودة إلى الورشة من جاهزة أو تعذّر الإصلاح. يمكن إعادة فتح تذكرة مستلمة خلال 24 ساعة، وبعدها يكون الرد 409 مع reason بقيمة REOPEN_WINDOW. يتلقى الزبون الإشعار نفسه، ويُحتسب الوفاء كما في التطبيق.

محتوى JSON

  • status string إلزامي

    ready أو impossible أو workshop أو collected.

POST/v1/tickets/{id}/notified

تم إعلام الزبون

أعلمت الزبون بنفسك.

أعلمت الزبون بنفسك برسالة أو مكالمة؟ أخبرنا بذلك لتظهر في صفحته.

محتوى JSON

  • channel string إلزامي

    sms أو whatsapp أو call.

الزبائن والوفاء

لا يرى المحل إلا الزبائن الذين يعرفونه: تذكرة قُبلت عنده أو مرور بالمحل. البحث عن رقم غير معروف، أو عن رقم زبون حظر المحل، يعطي الرد نفسه 404.

الاسم الظاهر يحترم اختيار الزبون: إن أخفى اسمه ترى « سناء ب. ».

GET/v1/clients

البحث عن زبون

بالهاتف، بين الزبائن الذين يعرفون المحل من قبل.

معاملات الرابط

  • phone string إلزامي

    الرقم بالصيغة الدولية.

GET/v1/clients/{id}

قراءة زبون

الاسم الظاهر والتذاكر المفتوحة ومجموعها وبطاقة الوفاء.

GET/v1/clients/{id}/loyalty

بطاقة الوفاء

برنامج المحل وبطاقة الزبون.

POST/v1/clients/{id}/loyalty/stamps

إضافة أختام

يضيف من 1 إلى 10 أختام إلى البطاقة.

الأختام والمكافآت تتطلب Idempotency-Key. عشرون ختمًا على الأكثر لكل زبون في اليوم ولكل مفتاح. إذا كان برنامج الوفاء متوقفًا فالرد 409 LOYALTY_OFF.

الترويسات

  • Idempotency-Key string إلزامي

    إلزامي.

محتوى JSON

  • count integer إلزامي

    من 1 إلى 10.

POST/v1/clients/{id}/loyalty/redeem

استعمال مكافأة

يستعمل مكافأة متاحة في البطاقة.

الترويسات

  • Idempotency-Key string إلزامي

    إلزامي.

Webhooks

أدخل عنوان https في التطبيق: يرسل إليه تفقدني طلب POST عند كل مرحلة من التذكرة. webhook واحد لكل محل.

  • ticket.createdأُنشئت تذكرة، من التطبيق أو عبر الواجهة البرمجية.
  • ticket.readyالتذكرة جاهزة.
  • ticket.impossibleسُجّلت التذكرة كمتعذّرة الإصلاح.
  • ticket.reopenedعادت التذكرة إلى الورشة.
  • client.notifiedأُعلِم الزبون (واتساب، التطبيق، رسالة، مكالمة).
  • ticket.collectedاستلم الزبون غرضه.
  • ticket.abandonedأُغلقت التذكرة: جاهزة ولم تُستلم (60 يومًا)، أو بقيت في الورشة دون أخبار (60 يومًا). قيمة reason هي uncollected أو no_news.
  • quote.acceptedقبل الزبون سعرًا جديدًا.
  • client.linkedرُبط زبون بالتذكرة.
  • pingزر « إرسال تجربة » في التطبيق.

التحقق من التوقيع

يحمل كل إرسال ترويسة Tfa9adni-Signature: قيمة t هي وقت الإرسال بالثواني، و v1 هي HMAC-SHA256 للنص « t.body » بسرّ الـ webhook، بالنظام الست عشري. احسبها على المحتوى الخام، وقارن في زمن ثابت، وارفض أي t يبعد أكثر من 5 دقائق. خلال 24 ساعة بعد تغيير السرّ تُرسل قيمتان v1.

ممارسات جيدة

  • أجب بـ 2xx في أقل من 10 ثوانٍ، ثم عالج الطلب لاحقًا.
  • قد يصل الحدث مرتين: استبعد المكرّر حسب id.
  • تجاهل الأنواع التي لا تعرفها: ستُضاف أنواع جديدة.
  • لسدّ أي نقص، أعد قراءة GET /v1/tickets?updated_since=.

دون ردّ 2xx، تُعاد المحاولة بعد دقيقة، ثم 5 دقائق، و30 دقيقة، وساعتين، و6 ساعات، و12 ساعة، و24 ساعة، ثم يُترك الإرسال. بعد 20 إخفاقًا متتاليًا خلال 72 ساعة، أو ردّ 410، يتوقف الـ webhook ويُعلَم صاحب المحل. لا تُتبع التحويلات، وتُرفض العناوين الخاصة.

الأخطاء

عند الخطأ تكون success بقيمة false ويبيّن error.code السبب. ويوضّح details.reason سبب الرد 409.

400 VALIDATION_ERROR محتوى أو مُعامِل غير صالح، ويبيّن details أيّها.
401 UNAUTHENTICATED مفتاح غائب أو خاطئ أو ملغى.
403 FORBIDDEN المفتاح لا يملك هذه الصلاحية (details.scope).
403 SHOP_NOT_APPROVED المحل لم يُوثَّق بعد.
403 ACCOUNT_DEACTIVATED المحل معطّل.
403 API_DISABLED الواجهة البرمجية غير مفتوحة لهذا المحل بعد.
404 NOT_FOUND غير موجود لهذا المحل.
409 CONFLICT غير ممكن في هذه الحالة (details.reason).
422 PROFANITY النص يحتوي على كلمة ممنوعة.
429 TOO_MANY_ATTEMPTS طلبات أو تذاكر كثيرة، أعد المحاولة لاحقًا.

الحدود

  • 120 في الدقيقةالطلبات لكل مفتاح
  • 30 في الدقيقةعمليات الكتابة لكل مفتاح
  • 150 في الساعة، 600 في اليومالتذاكر لكل محل (التطبيق والواجهة معًا)
  • 60 في الساعة، 300 في اليومالبحث عن زبون برقم الهاتف

يحمل كل ردّ الترويسات RateLimit-Limit و RateLimit-Remaining و RateLimit-Reset. بعد تجاوز الحد يكون الرد 429: انتظر عدد الثواني في RateLimit-Reset.