انتقل إلى المقال
Aniq-UI

Northstackمرجع واجهة API

مرجع واجهة API

كل مسار تقدّمه واجهة API، ومن يستطيع استدعاءه، وكيف يعمل تسجيل الدخول ومساحات العمل والصلاحيات والفوترة ومفاتيح API والأخطاء والقوائم والحدود.

لحزمة الحزمة الكاملة

العنوان الأساسي وصيغة الاستجابة

كل مسار يُقدَّم تحت البادئة /api. محليًا يكون العنوان الأساسي http://localhost:8000/api. وعلى الخادم يكون عنوان واجهة API متبوعًا بـ /api، وهو القيمة نفسها التي يقرؤها الموقع ولوحة التحكم من NEXT_PUBLIC_API_BASE_URL (متغيرات البيئة). الملفات تُقدَّم خارج البادئة: ملفات هوية الحزمة على /media/… والملفات المرفوعة على /media/uploads/….

أجسام الطلبات بصيغة JSON، باستثناء رفع الملفات. وكل إجابة تأتي في المغلّف نفسه:

الغلاف
{
  "success": true,
  "data": { },
  "message": ""
}

يحمل data النتيجة. أما message فهو رمز قصير تملؤه بعض عمليات الكتابة، مثل project_created أو invitation_sent، ويكون فارغًا في غير ذلك. تُسمّى مساحات العمل والمشاريع والمهام بمعرّفاتها العامة (org_forma وprj_01)؛ والأعضاء والدعوات والمفاتيح والملفات برقمها. وتحمل نصوص المشاريع والمهام اللغتين معًا بالشكل { "en": { … }, "ar": { … } }.

فحص السلامة لا يحتاج إلى رمز:

الطرفية
curl http://localhost:8000/api/health
الاستجابة
{"success":true,"data":{"status":"ok","database":"up"},"message":""}

إلى أن تجيب قاعدة البيانات وتصبح جداولها جاهزة، تجيب الواجهة بـ 503 مع "status":"unavailable" و"database":"down". يقرأ فحص الصحة في صورة Docker هذه الحالة، ولا يشغّل Docker Compose الموقع ولوحة التحكم إلا بعد أن ينجح.

لا يجوز للمتصفحات استدعاء واجهة API إلا من العناوين الواردة في CORS_ORIGIN. وإذا تُرك غير مضبوط فهي تسمح بـ http://localhost:3030 وhttp://localhost:3031، وفي الإنتاج ترفض الواجهة البدء من دونه (مشكلات CORS).

الأخطاء

يحتفظ الفشل بالمغلّف نفسه، مع success: false وdata: null ورمز حالة HTTP:

الخطأ
{
  "success": false,
  "data": null,
  "message": "seat_limit_reached",
  "errors": { "email": ["…"] }
}
  • يظهر errors عند فشل التحقق (400)، مع المشكلات لكل حقل.
  • أي حقل غير معروف في الجسم يُرفض بالرمز 400: كل جسم يقبل الحقول المذكورة أدناه فقط.
  • عندما يكون لدى واجهة API جملة للخطأ، يكون message تلك الجملة بلغة الطلب (Accept-Language: ar للعربية): تسجيل دخول مرفوض، وكل 429، والتسجيل المغلق، وحساب محمي من تغيير كلمة المرور أو البريد، وسر webhook مفقود، واشتراك تعذّر على Stripe إلغاؤه، ودور منصة أو صلاحية لا يملكها المستدعي، ووضع الصيانة.
  • وفي غير ذلك، يكون message في 401 و403 و404 جملة عامة للحالة، وفي 400 و402 و409 و410 و503 يكون السبب رمزًا قصيرًا (seat_limit_reached وslug_taken وover_plan_limit وpayment_declined وpreview_expired وinvitation_expired وpayment_unavailable)، يحوّله العميل إلى جملته الخاصة. والتخفيض المرفوض بسبب الاستخدام يحمل blockers أيضًا.
  • يعني 402 ترقية خطة لم يقبل مزود الدفع تحصيلها: payment_declined أو payment_needs_action (يطلب المصرف تأكيد الدفعة) أو payment_method_missing. وتبقى الخطة كما كانت.
  • أثناء تفعيل طاقم المنصة لوضع الصيانة، يجيب كل مسار خارج القائمة القصيرة في وضع الصيانة بـ 503 لأي شخص ليس من طاقم المنصة، مع الجملة في message وcode: "maintenance_mode".
  • يعني 401 عدم وجود رمز، أو رمزًا منتهيًا، أو بيانات دخول خاطئة. ويعني 403 تسجيل دخول بلا الصلاحية، أو كتابة في مساحة عمل موقوفة. ويجيب 404 أيضًا عن مساحة عمل ليس المستدعي عضوًا فيها، فلا يعرف الغريب أي مساحات عمل موجودة.
  • الطلب الذي يتجاوز حدًّا يُجاب بـ 429 (الحدود لكل عنوان).

تسجيل الدخول

  1. تسجيل الدخول

    الطرفية
    curl -X POST http://localhost:8000/api/auth/login \
      -H "Content-Type: application/json" \
      -d '{"email":"owner@northstack.example","password":"YOUR_PASSWORD"}'

    ضع بيانات الدخول الأولية من التثبيت مكان YOUR_PASSWORD، أو استخدم حسابًا خاصًا بك. data.access_token هو الرمز، ومعه token_type بقيمة Bearer وexpires_in وadmin، وهو الحساب مع أدوار المنصة وصلاحياته ومساحات عمله.

  2. استدعِ مسارًا محميًا

    الطرفية
    curl http://localhost:8000/api/workspaces \
      -H "Authorization: Bearer YOUR_TOKEN"

    يسرد هذا مساحات عمل الحساب مع دوره في كل منها. ثم يأخذ كل مسار لمساحة عمل معرّفها العام في مساره:

    الطرفية
    curl "http://localhost:8000/api/workspaces/org_forma/projects?limit=20" \
      -H "Authorization: Bearer YOUR_TOKEN"
  • remember: true يوقّع رمزًا لمدة 30 يومًا، وremember: false رمزًا لمدة 12 ساعة؛ وإذا حُذف فالرمز يدوم بحسب JWT_EXPIRATION، وهو 7d افتراضيًا.
  • بريد غير معروف وكلمة مرور خاطئة يُجابان بـ 401 بالرسالة نفسها، بعد العمل نفسه من تجزئة كلمة المرور، فلا تدل الإجابة ولا زمنها على البريد الذي له حساب.
  • عشر محاولات دخول فاشلة من عنوان واحد خلال 15 دقيقة تُجاب بـ 429 حتى يمضي 15 دقيقة على أقدم محاولة فاشلة (RATE_LIMIT_LOGIN). ولا تُحتسب عمليات الدخول الناجحة.
  • الرموز بلا حالة: يجيب POST /api/auth/logout فورًا، وتسجيل الخروج هو أن ينسى العميل رمزه.
الطريقةالمسارمن يحق له استدعاؤهوظيفته
POST/api/auth/loginأي شخصتسجيل الدخول: email وpassword، وremember اختياريًا
POST/api/auth/signupأي شخصحساب جديد، يسجَّل دخوله فورًا وجاهز للتهيئة: name (من 2 إلى 80 حرفًا) وemail وpassword (من 8 إلى 128) وacceptTerms (true). البريد المستخدم يُجاب بـ 409 مع email_taken؛ وعندما يكون إعداد المنصة signups_enabled متوقفًا يُجاب بـ 403
POST/api/auth/forgot-passwordأي شخصemail، وlocale اختياريًا (en وar). يرسل بالبريد رابط إعادة تعيين يعمل مرة واحدة لمدة ساعة إذا كان الحساب موجودًا، ويجيب بالطريقة نفسها في الحالتين
POST/api/auth/reset-passwordأي شخصtoken (من الرابط) وpassword الجديدة (من 8 إلى 128). الرابط المستخدم أو المنتهي يُجاب بـ 401
POST/api/auth/logoutأي شخصيجيب بـ { signedOut: true }
GET/api/auth/meأي حساب مسجّل الدخولالحساب وأدوار المنصة وصلاحياته ومساحات عمله
PATCH/api/auth/meأي حساب مسجّل الدخولتغيير firstName أو lastName أو email أو phone
PATCH/api/auth/me/preferencesأي حساب مسجّل الدخولtheme (system وlight وdark) وreducedMotion وlocale (en وar) وlastWorkspaceId، وهي مساحة العمل التي يفتحها تسجيل الدخول التالي
PATCH/api/admins/profile/passwordأي حساب مسجّل الدخولتغيير كلمة مرور الحساب نفسه: current_password وpassword وpassword_confirmation

مساحات العمل والصلاحيات

  • مسارات مساحة العمل تبدأ بـ /api/workspaces/:workspaceId، وهو المعرّف العام لمساحة العمل. في كل طلب تتحقق واجهة API من أن المستدعي له عضوية نشطة هناك (وإلا 404) ويملك الصلاحية التي يذكرها المسار (وإلا 403). الدور هو دور العضوية: يمكن لشخص واحد أن يكون مالك مساحة عمل ومسؤولًا في أخرى.
  • تضم مساحة العمل أربعة أدوار (owner وadmin وmember وbilling) ومصفوفتها الخاصة من 14 صلاحية: workspace.read وworkspace.update وworkspace.delete وprojects.read وprojects.write وmembers.invite وmembers.remove وroles.manage وbilling.read وbilling.manage وkeys.manage وaudit.read وai.read وai.apply. يملكها المالك كلها، وتبقى workspace.delete وroles.manage للمالك مهما قالت المصفوفة. وأي تغيير في المصفوفة يسري على الطلب التالي.
  • مساحة العمل الموقوفة تحتفظ بكل طلبات GET وترفض كل طريقة أخرى بالرمز 403.
  • مساحة العمل المتأخرة في الدفع تحتفظ بكل شيء حتى تمر BILLING_GRACE_DAYS (7 افتراضيًا)؛ بعدها لا تستطيع إنشاء مشاريع أو دعوات أو مفاتيح API (403)، بينما تستمر كل القراءات وكل عمليات الكتابة الأخرى.
  • مسارات المنصة (/api/platform و/api/users و/api/admins و/api/roles و/api/settings) تتحقق بدلًا من ذلك من صلاحيات المنصة للحساب، وتُمنح عبر أدوار المنصة. ينشئ البذر مسؤول المنصة، بكل الصلاحيات الـ 21، والدعم، الذي يقرأ كل صفحات المنصة ويصدّر التقارير. والمسار الذي يذكر عدة صلاحيات يقبل أيًّا منها.

القوائم والتقسيم إلى صفحات

قائمة
{ "data": [ ], "total": 12, "page": 1, "limit": 7, "totalPages": 2 }
  • المشاريع، والمشاريع المؤرشفة، والنشاط، ومحادثات المساعد ورسائلها، وصفحة مؤسسات المنصة ومستخدميها، تستخدم page وlimit، بحد أقصى 100 في الصفحة. القيم الافتراضية 7 مشاريع و12 حدثًا و20 محادثة و10 مؤسسات أو مستخدمين.
  • صفحات الطاقم وإعدادات المنصة وأدوارها تستخدم page وpage_count بدلًا من ذلك (10 افتراضيًا، وبحد أقصى 100). وأدوار المنصة لا تُقسَّم إلى صفحات إلا عند إعطاء الاثنين معًا؛ وإلا تُعاد كل الأدوار.
  • تأتي القوائم من الأحدث أولًا (المشاريع والمستخدمون والمؤسسات بحسب آخر تغيير)، مع المعرّف عند التعادل، ما لم يُعطَ sort؛ وتأتي أدوار المنصة بحسب الاسم. وتعيد قائمة المشاريع أيضًا counts لكل تبويب.
  • ما يخص مساحة عمل واحدة ويُعرض كاملًا يُجاب دون تقسيم إلى صفحات: مهام اللوحة، والأعضاء، والدعوات، ومفاتيح API، وملفات المشروع، وآخر 36 فاتورة، وآخر 8 إشعارات.

مساحات العمل والأعضاء ومصفوفة الأدوار

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspacesأي حساب مسجّل الدخولمساحات عمل الحساب مع دوره في كل منها، لمبدّل مساحات العمل
GET/api/workspaces/slug-availabilityأي حساب مسجّل الدخول?slug=: هل عنوان مساحة العمل متاح، مع suggestion عندما لا يكون كذلك
POST/api/workspacesأي حساب مسجّل الدخولالتهيئة: name (من 2 إلى 80) وslug (من 3 إلى 48 من الأحرف الصغيرة والأرقام والواصلات) وregion (europe وnorth_america وasia_pacific)، وinvitations اختياريًا، حتى 20 عنصرًا { email, role }. يصبح المستدعي المالك، على فترة تجريبية للخطة Starter بمدة trial_days للمنصة. الـ slug المستخدم يُجاب بـ 409 مع slug_taken، وعندما يكون signups_enabled متوقفًا يُجاب بـ 403
GET/api/workspaces/:workspaceIdعضو لديه workspace.readمساحة العمل: الاسم والعنوان والخطة والاستخدام مقابل حدود الخطة وإعداداتها. تكون billingEmail بقيمة null ما لم يملك المستدعي billing.read أو billing.manage
PATCH/api/workspaces/:workspaceIdعضو لديه workspace.updateتغيير name أو slug أو locale (en وar) أو timeZone (منطقة IANA مثل Europe/Berlin) أو domainConfigured أو emailNotifications (رسائل الفوترة) أو weeklyDigest
DELETE/api/workspaces/:workspaceIdمالك مساحة العملconfirmName (اسم مساحة العمل مكتوبًا) وpassword الخاصة بالمالك. تُحذف مساحة العمل حذفًا ناعمًا، ويُلغى اشتراكها في Stripe أولًا؛ وإذا رفض Stripe يُجاب بـ 409 وتبقى مساحة العمل
GET/api/workspaces/:workspaceId/membersعضو لديه workspace.readالأعضاء مع أدوارهم. search وrole
PATCH/api/workspaces/:workspaceId/members/:memberIdعضو لديه roles.manageتغيير role للعضو (admin وmember وbilling). صف المالك يُجاب بـ 403
DELETE/api/workspaces/:workspaceId/members/:memberIdعضو لديه members.removeإزالة عضو. لا يمكن إزالة المالك، ولا يجوز للمسؤول إزالة مسؤول آخر
POST/api/workspaces/:workspaceId/members/transfer-ownershipمالك مساحة العملmemberId وpassword الخاصة بالمالك. يصبح العضو هو المالك ويصبح المالك السابق مسؤولًا
GET/api/workspaces/:workspaceId/rolesعضو لديه workspace.readمصفوفة الأدوار: كل صلاحية، في ست مجموعات، والأدوار التي تملكها
PUT/api/workspaces/:workspaceId/rolesمالك مساحة العملحفظ المصفوفة: matrix، وفيها كل صلاحية مرتبطة بالأدوار التي تملكها. الصلاحية أو الدور غير المعروف يُجاب بـ 400

الدعوات

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/invitationsعضو لديه workspace.readstatus (pending، وهو الافتراضي، أو all). يجيب بـ invitations وseats، أي المقاعد المستخدمة والمتبقية في الخطة
POST/api/workspaces/:workspaceId/invitationsعضو لديه members.inviteدعوة email بدور role (admin وmember وbilling). يُرسل الرابط بالبريد ويعمل 7 أيام. الخطة الممتلئة تُجاب بـ 409 مع seat_limit_reached؛ ويُرفض already_member وalready_invited بالطريقة نفسها
POST/api/workspaces/:workspaceId/invitations/:id/resendعضو لديه members.inviteرابط جديد صالح 7 أيام أخرى. مرة واحدة في الدقيقة على الأكثر (resend_too_soon)، وخمس مرات لكل دعوة (resend_limit_reached)
DELETE/api/workspaces/:workspaceId/invitations/:idعضو لديه members.inviteإلغاء دعوة
GET/api/invitations/:tokenأي شخصما يفتحه رابط الدعوة: اسم مساحة العمل وعنوانها، والدور، والبريد المدعو مخفيًا جزئيًا، وهل ما زالت الدعوة مفتوحة
POST/api/invitations/:token/acceptالحساب المدعو، وقد سُجّل دخولهالانضمام إلى مساحة العمل. الرابط المنتهي أو الملغى يُجاب بـ 410؛ والحساب الذي بريده غير البريد المدعو يُجاب بـ 403؛ والخطة الممتلئة تُجاب بـ 409 مع seat_limit_reached

تمر رسائل الدعوة عبر إعدادات SMTP الخاصة بواجهة API، أو تذهب إلى سجلها ما دام SMTP_HOST فارغًا، مع الرابط.

المشاريع والملفات

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/projectsعضو لديه projects.readالمشاريع مع counts لكل تبويب. status (all أو active أو completed أو حالة واحدة) وstate (in_progress وreview وblocked وcompleted) وsearch وownerId وdueBefore (YYYY-MM-DD) وsort (updated_at وdue_date وname وprogress) وorder (asc وdesc) وpage وlimit
GET/api/workspaces/:workspaceId/projects/archivedعضو لديه projects.readالمشاريع المؤرشفة، بالمرشّحات نفسها
GET/api/workspaces/:workspaceId/projects/ownersعضو لديه projects.readالأعضاء الذين يملكون مشاريع، لمرشّح المالك
GET/api/workspaces/:workspaceId/projects/:projectIdعضو لديه projects.readمشروع واحد مع مالكه وتاريخ استحقاقه وتقدمه وعدد مهامه
POST/api/workspaces/:workspaceId/projectsعضو لديه projects.writeإنشاء مشروع: translations (en مطلوب وar اختياري، في كل منهما name حتى 120 حرفًا وdescription حتى 2000)، واختياريًا status وownerId (عضو) وdueDate (YYYY-MM-DD) وprogress (من 0 إلى 100)
PATCH/api/workspaces/:workspaceId/projects/:projectIdعضو لديه projects.writeتغيير أي من هذه الحقول
DELETE/api/workspaces/:workspaceId/projects/:projectIdعضو لديه projects.writeأرشفة مشروع. لا يُحذف شيء
POST/api/workspaces/:workspaceId/projects/:projectId/restoreعضو لديه projects.writeإعادة مشروع مؤرشف
GET/api/workspaces/:workspaceId/projects/:projectId/activityعضو لديه projects.readآخر 100 حدث في المشروع
GET/api/workspaces/:workspaceId/projects/:projectId/filesعضو لديه projects.readملفات المشروع، من الأحدث
POST/api/workspaces/:workspaceId/projects/:projectId/filesعضو لديه projects.writeإرفاق ملف: file بصيغة multipart، 10 ميغابايت على الأكثر. يُحتسب حجمه من تخزين الخطة
GET/api/workspaces/:workspaceId/projects/:projectId/files/:fileId/downloadعضو لديه projects.readurl الملف وname وmime

إنشاء مشروع في مساحة عمل متأخرة في الدفع انتهت مهلتها يُجاب بـ 403.

المهام واللوحة

تُعرض المهمة وتُنشأ تحت مشروعها، وتُغيَّر بمعرّفها الخاص تحت مساحة العمل.

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/projects/:projectId/tasksعضو لديه projects.readمهام اللوحة بترتيب الأعمدة. assigneeId وpriority وsearch
POST/api/workspaces/:workspaceId/projects/:projectId/tasksعضو لديه projects.writeإنشاء مهمة: translations (en مطلوب، في كل منهما title حتى 160 حرفًا وdescription حتى 4000)، واختياريًا status (backlog، وهو الافتراضي، وin_progress وreview وdone) وpriority (low وnormal وhigh) وassigneeId (عضو) وdueDate
PATCH/api/workspaces/:workspaceId/tasks/:taskIdعضو لديه projects.writeتغيير أي من هذه الحقول
POST/api/workspaces/:workspaceId/tasks/:taskId/moveعضو لديه projects.writeنقل بطاقة: status (العمود) وbeforeId، وهي البطاقة التي تستقر فوقها، أو لا شيء لنهاية العمود
DELETE/api/workspaces/:workspaceId/tasks/:taskIdعضو لديه projects.writeأرشفة مهمة

المسؤول عن المهمة إذا لم يكن عضوًا يُجاب بـ 400 مع assignee_not_member. كل تغيير يكتب حدثًا في سجل النشاط، مثل task.moved مع العمودين اللذين انتقلت منهما وإليهما.

النظرة العامة والنشاط والإشعارات والبحث

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/overviewعضو لديه workspace.readالنظرة العامة: المشاريع بحسب الحالة، والأعضاء والدعوات المعلقة، وأحداث المهام في كل يوم خلال آخر سبعة أيام، وقائمة الإطلاق، وحتى ثلاثة مشاريع يحل موعدها خلال الفترة، وآخر ستة أحداث. period (7d و30d، وهو الافتراضي، و90d). بدون projects.read تعود أعداد المشاريع والرسم البياني والمشاريع المستحقة أصفارًا أو فارغة
GET/api/workspaces/:workspaceId/activityعضو لديه audit.readسجل النشاط، مع الأشخاص فيه في actors. action (إجراء واحد مثل task.moved، أو عائلة تنتهي بنقطة مثل task.) وactorId وfrom وto (YYYY-MM-DD) وsearch وpage وlimit
GET/api/workspaces/:workspaceId/activity/exportعضو لديه audit.readالمرشّحات نفسها بصيغة ملف CSV (date وactor وaction وsubject وdetails)، حتى 5,000 صف. تُهرَّب الخلايا التي قد تعمل كمعادلة جدول بيانات
GET/api/workspaces/:workspaceId/notificationsعضو لديه workspace.readالجرس: آخر 8 أحداث وعدد الأحداث الأحدث من آخر اطلاع للقارئ
POST/api/workspaces/:workspaceId/notifications/readعضو لديه workspace.readتعليم كل شيء حتى الآن كمقروء
GET/api/workspaces/:workspaceId/searchعضو لديه workspace.readq (من 2 إلى 100 حرف): حتى خمسة مشاريع ومهام وأعضاء من كل نوع. المشاريع والمهام لا تظهر إلا لعضو لديه projects.read

تعرض آخر أحداث النظرة العامة والجرس السجل كاملًا لمن لديه projects.read أو audit.read، وأحداث billing. فقط لمن لديه billing.read ولا يملك أيًّا من الصلاحيتين السابقتين، ولا شيء لأي شخص آخر.

الفوترة وwebhook الخاص بها والدفع التجريبي

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/billingعضو لديه billing.readالاشتراك: الخطة والحالة والسعر والتجديد، وإلغاء أو تخفيض ينتظر التجديد، ومهلة التأخر في الدفع، والاستخدام، وأي دفع قيد التنفيذ
GET/api/workspaces/:workspaceId/billing/invoicesعضو لديه billing.readآخر 36 فاتورة
GET/api/workspaces/:workspaceId/billing/invoices/:invoiceId/download-linkعضو لديه billing.readرابط موقّع لملف PDF الخاص بالفاتورة، صالح خمس دقائق، مبني من PUBLIC_API_URL
POST/api/workspaces/:workspaceId/billing/previewعضو لديه billing.manageما تكلفه الخطة planId (starter وpro وscale): ترقية أم تخفيض، ومتى يسري، ورسوم اليوم (chargeTodayCents)، والفاتورة التالية وأي blockers (المقاعد أو طلبات API أو التخزين فوق حدود الخطة الأصغر). ترقية اشتراك Stripe قائم يسعّرها Stripe ويجيب بـ chargesCardOnFile: true مع quote يثبّت ذلك السعر 30 دقيقة؛ أما الدفع التجريبي فيوزّع الفرق بالتناسب على بقية الفترة. الخطة الحالية تُجاب بـ 400 مع same_plan، إلا في أول دفعة (فترة تجريبية أو فترة منتهية أو مساحة عمل ملغاة)، حيث تُحصَّل أي خطة بسعرها الكامل
POST/api/workspaces/:workspaceId/billing/checkoutعضو لديه billing.manageplanId، وlocale اختياريًا، وquote المعاينة. ترقية اشتراك Stripe قائم تتم فورًا وتُحصَّل من وسيلة الدفع المحفوظة (upgraded: true) مع بقاء تاريخ التجديد كما هو؛ والتحصيل المرفوض يُجاب بـ 402 مع payment_declined أو payment_needs_action أو payment_method_missing، والـ quote المنتهي أو الغريب بـ 409 مع preview_expired. وأي ترقية أخرى تجيب بـ url صفحة الدفع المستضافة وsession. أما التخفيض فيُجدول للتجديد (scheduled: true)، وفي Stripe عبر جدول اشتراك، أو يُرفض بـ 409 مع over_plan_limit وblockers
POST/api/workspaces/:workspaceId/billing/checkout/:sessionId/syncعضو لديه billing.readبعد العودة من صفحة الدفع: تُقرأ الجلسة من المزود ويُجاب بالجلسة والملخص. لا تتغير الخطة إلا بعد أن يقول المزود إنها مدفوعة
POST/api/workspaces/:workspaceId/billing/keep-planعضو لديه billing.manageالتراجع عن تخفيض مجدول للتجديد؛ ويجيب بالملخص. وإذا لم يكن هناك شيء مجدول يُجاب بـ 409 مع no_scheduled_change
POST/api/workspaces/:workspaceId/billing/portalعضو لديه billing.manageurl بوابة عملاء Stripe، لوسيلة الدفع؛ وurl: null لمساحة عمل لا تُفوتَر عبر Stripe
POST/api/workspaces/:workspaceId/billing/cancelعضو لديه billing.manageالإلغاء في نهاية الفترة. يُسقَط أي تخفيض مجدول للتجديد
POST/api/workspaces/:workspaceId/billing/resumeعضو لديه billing.manageالإبقاء على اشتراك كان مضبوطًا للإلغاء
PATCH/api/workspaces/:workspaceId/billing/emailعضو لديه billing.manageتغيير email الفوترة
GET/api/billing/invoices/downloadأي شخص يملك الرابط الموقّع?token=: الفاتورة بصيغة PDF. الرمز الخاطئ يُجاب بـ 401 والمنتهي بـ 403
POST/api/billing/webhooks/stripeStripeأحداث Stripe، يُتحقق منها بـ STRIPE_WEBHOOK_SECRET مقابل الترويسة Stripe-Signature؛ التوقيع المفقود أو الخاطئ يُجاب بـ 400، وكذلك كل تسليم ما دام STRIPE_WEBHOOK_SECRET فارغًا، مع رسالة تذكره. تستخدم الاشتراكات checkout.session.completed وinvoice.paid وinvoice.payment_failed وcustomer.subscription.deleted، ويُطبَّق معرّف كل حدث مرة واحدة. وتصل طلبات التراخيص على المسار نفسه (الدفع لشراء التراخيص)
GET/api/billing/simulator/:sessionIdعضو لديه billing.manage في مساحة عمل الجلسةجلسة الدفع التجريبي، لصفحة الدفع الخاصة بلوحة التحكم
POST/api/billing/simulator/:sessionId/completeعضو لديه billing.manage في مساحة عمل الجلسةدفع تجريبي: تتغير الخطة كما لو أكّد المزود الدفع
POST/api/billing/simulator/:sessionId/cancelعضو لديه billing.manage في مساحة عمل الجلسةترك الدفع التجريبي دون دفع
  • يستخدم الدفع Stripe Checkout عندما يكون STRIPE_SECRET_KEY مضبوطًا، والدفع التجريبي المدمج في غير ذلك، أو متى كان BILLING_PROVIDER=simulator. الدفع التجريبي لا يحصّل من أحد.
  • عنوان العودة وحده لا يغيّر الخطة أبدًا: يغيّرها فقط الـ webhook الموقّع، أو الجلسة المقروءة عند sync.
  • يُنشأ سعر Stripe لكل خطة عند أول استخدام، بمفتاح البحث northstack_<plan>_usd_<cents>_month، فلا يلزم إعداد أي شيء في Stripe أولًا.
  • إتمام دفع Stripe لمساحة عمل لديها اشتراك Stripe بالفعل يلغي القديم، مع احتساب وقته غير المستخدم رصيدًا. يخزّن invoice.paid فاتورة Stripe مرة واحدة (الفواتير فريدة لكل معرّف فاتورة عند المزود)، مع مبلغها وفترتها، وينقل فترة مساحة العمل إلى الفترة التي تبدأ بها الفاتورة، وعند التجديد يطبّق التخفيض المجدول له.
  • في الدفع التجريبي تجدد واجهة API كل فترة عند نهايتها (فاتورة مدفوعة، و30 يومًا تالية، وتخفيض مجدول يُطبَّق) وتنهي ما ضُبط للإلغاء. والفترة التجريبية التي تبلغ نهايتها تصبح متأخرة في الدفع، مع مهلة السماح. وتبدأ عدادات الاستخدام من الصفر في كل فترة. يجري هذا عند كل قراءة للفوترة ومرة كل ساعة.
  • وجّه webhook الخاص بـ Stripe إلى https://<your API>/api/billing/webhooks/stripe مع الأحداث أعلاه إضافة إلى checkout.session.expired.

مفاتيح API وواجهة API العامة

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/workspaces/:workspaceId/api-keysعضو لديه keys.manageمفاتيح مساحة العمل: الاسم والبادئة والنطاقات والبيئة وآخر استخدام ومن أنشأها. من دون السر أبدًا
POST/api/workspaces/:workspaceId/api-keysعضو لديه keys.managename (من 2 إلى 60) وscopes (واحد أو أكثر من projects:read وprojects:write وtasks:read وtasks:write) وenvironment (production، وهو الافتراضي، أو demo). يجيب بالمفتاح مع secret الذي يظهر هذه المرة فقط؛ ولا يُحفظ منه إلا تجزئة SHA-256
DELETE/api/workspaces/:workspaceId/api-keys/:idعضو لديه keys.manageإلغاء مفتاح. يتوقف عن العمل فورًا
GET/api/v1/projectsمفتاح API لديه projects:readأحدث 100 مشروع تحديثًا في مساحة العمل
POST/api/v1/projectsمفتاح API لديه projects:writeإنشاء مشروع، بالجسم نفسه الذي تستخدمه لوحة التحكم
PATCH/api/v1/projects/:projectIdمفتاح API لديه projects:writeتغيير مشروع، بالجسم نفسه الذي تستخدمه لوحة التحكم
GET/api/v1/projects/:projectId/tasksمفتاح API لديه tasks:readمهام مشروع واحد
POST/api/v1/projects/:projectId/tasksمفتاح API لديه tasks:writeإنشاء مهمة، بالجسم نفسه الذي تستخدمه اللوحة
الطرفية
curl http://localhost:8000/api/v1/projects \
  -H "Authorization: Bearer nst_live_…"
  • يبدأ سر مفتاح الإنتاج بـ nst_live_، ومفتاح العرض بـ nst_demo_. ولا يعمل مفتاح العرض إلا ما دامت واجهة API في الوضع التجريبي.
  • من دون مفتاح، أو بمفتاح غير معروف أو ملغى، يُجاب بـ 401؛ والمفتاح الذي لا يملك نطاق المسار يُجاب بـ 403؛ ومساحة العمل الموقوفة ترفض الكتابة.
  • كل مسار عدا قائمة المشاريع يعمل بصفة منشئ المفتاح: ما ينشئه يُسجَّل على أنه من صنعه، مع تحقق لوحة التحكم وأحداث النشاط وحدود الخطة. ويُجاب بـ 404 متى غادر المنشئ مساحة العمل، وتُجاب عمليات الكتابة الثلاث بـ 403 متى لم يعد دور المنشئ يملك projects.write.
  • كل استدعاء يُحتسب ضمن طلبات API الخاصة بالخطة، التي تقرؤها صفحة الفوترة وحدود الخطة.

نظرة عامة على المنصة والمؤسسات

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/platform/overviewطاقم لديه platform.viewالإيرادات الشهرية المتكررة وتاريخها، وتوزيع الخطط، والمؤسسات بحسب الحالة. range (30d و90d و6m، وهو الافتراضي، و12m)
GET/api/platform/overview/exportطاقم لديه reports.exportكل المؤسسات بصيغة ملف CSV: organization وid وplan وstatus وseats وmrr_usd وcreated
GET/api/platform/organizationsطاقم لديه organizations.viewالمؤسسات. search (الاسم أو العنوان) وplan (starter وpro وscale) وstatus (trialing وactive وpast_due وcanceling وcanceled وsuspended) وpage وlimit
GET/api/platform/organizations/:idطاقم لديه organizations.viewمؤسسة واحدة، بمعرّفها العام
POST/api/platform/organizations/:id/suspendطاقم لديه organizations.managereason (من 3 إلى 300 حرف). تحتفظ مساحة العمل بقراءاتها وترفض كل كتابة. والموقوفة أصلًا تُجاب بـ 409
POST/api/platform/organizations/:id/reactivateطاقم لديه organizations.manageرفع الإيقاف

المستخدمون والطاقم وأدوار المنصة والإعدادات

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/usersطاقم لديه users.viewكل الحسابات. search وrole (owner أو admin أو member أو billing لدور مساحة عمل يشغله الحساب في أي مكان، وstaff لدور منصة، وnone للحسابات التي ليست في أي مساحة عمل) وpage وlimit
GET/api/users/deletedطاقم لديه users.viewالحسابات المحذوفة، بالمرشّحات نفسها
GET/api/users/statisticطاقم لديه users.viewالإجماليات: الحسابات، والمحذوفة، والطاقم، ومن بلا مساحة عمل، والجديدة في آخر 30 يومًا
GET/api/users/deleted/:usernameطاقم لديه users.viewحساب محذوف واحد
GET/api/users/:usernameطاقم لديه users.viewحساب واحد
POST/api/usersطاقم لديه users.createإنشاء حساب: first_name وlast_name وemail وpassword (من 8 إلى 128)، وphone اختياريًا
PATCH/api/users/:usernameطاقم لديه users.updateتغيير first_name أو last_name أو email أو phone. البريد الجديد يخضع للحماية الموضحة أدناه
PATCH/api/users/:username/change-passwordطاقم لديه users.updateتعيين password جديدة (من 8 إلى 128)، وتخضع للحماية الموضحة أدناه
DELETE/api/users/:usernameطاقم لديه users.deleteنقل حساب إلى قائمة المحذوفين. الحساب الذي يملك مساحة عمل يُجاب بـ 409 مع user_owns_workspace إلى أن تنتقل الملكية
POST/api/users/deleted/:username/restoreطاقم لديه users.restoreإعادة حساب محذوف
GET/api/adminsطاقم لديه admins.viewكل حساب مع أدوار المنصة. email وname (الاسم الأول أو الأخير أو اسم المستخدم) وphone، ويُرجَع الصف المطابق لأي واحد منها، وpage وpage_count
GET/api/admins/statisticsطاقم لديه admins.viewأعداد لصفحة الطاقم
GET/api/admins/:idطاقم لديه admins.viewحساب واحد، بالمعرّف أو اسم المستخدم
POST/api/adminsطاقم لديه admins.createإضافة حساب طاقم: first_name وlast_name وemail وpassword وpassword_confirmation (6 أحرف أو أكثر)، وphone وphone_code وprofile_picture اختياريًا
PATCH/api/admins/:idطاقم لديه admins.editتغيير هذه الحقول؛ وكلمة المرور الجديدة أو البريد الجديد يخضعان للحماية الموضحة أدناه
PATCH/api/admins/:id/rolesطاقم لديه admins.assign_rolesتعيين أدوار المنصة للحساب: role_ids. كل دور يُمنح أو يُسحب يجب ألا يضم إلا صلاحيات يملكها المستدعي نفسه، وإلا يُجاب بـ 403 (role_outranks_caller). وتُبلَّغ لوحة التحكم المفتوحة لديه فورًا
DELETE/api/admins/:idطاقم لديه admins.deleteإزالة حساب. الذي يملك مساحة عمل يُجاب بـ 409
PATCH/api/admins/profileطاقم لديه admins.editتغيير الملف الشخصي لعضو الطاقم المسجَّل دخوله
GET/api/rolesطاقم لديه roles.viewأدوار المنصة. name وguard_name وcreated_from وcreated_to وpage وpage_count
GET/api/roles/statisticsطاقم لديه roles.viewأعداد لصفحة الأدوار
GET/api/roles/selectطاقم لديه roles.viewمعرّف كل دور واسمه، لقائمة الاختيار
GET/api/roles/permissionsطاقم لديه roles.viewكل صلاحيات المنصة، مجمّعة بحسب المجال
GET/api/roles/:idطاقم لديه roles.viewدور واحد بصلاحياته
POST/api/rolesطاقم لديه roles.createإضافة دور: name. الاسم المستخدم يُجاب بـ 409
PUT/api/roles/:idطاقم لديه roles.editإعادة تسمية دور: name
POST/api/roles/:id/permissionsطاقم لديه roles.assign_permissionsتعيين permissions الدور، بالاسم. لا يجوز للمستدعي إعطاء إلا الصلاحيات التي يملكها، ولا تغيير إلا دور لا يضم صلاحية ينقصه، وإلا يُجاب بـ 403 (permission_outranks_caller). ويُبلَّغ كل من يحمله فورًا
DELETE/api/roles/:idطاقم لديه roles.deleteحذف دور. الدور الذي يحمله أحد يُجاب بـ 400
GET/api/settingsطاقم لديه settings.viewإعدادات المنصة. search وcategory وpage وpage_count
GET/api/settings/:keyطاقم لديه settings.viewإعداد واحد
PATCH/api/settings/:keyطاقم لديه settings.editتغيير إعداد واحد: value
DELETE/api/settings/:keyطاقم لديه settings.editاحذف إعدادًا واحدًا

الحماية على كلمات المرور والبريد: لا يجوز لمستدعٍ غير الحساب نفسه تعيين كلمة مرور الحساب أو تغيير بريده إلا إذا كان مسؤول المنصة أو يملك كل صلاحية منصة يملكها الحساب؛ وإلا تُجيب واجهة API بـ 403. والبريد محمي أيضًا لأن رابط إعادة تعيين كلمة المرور يُرسل إليه.

الحماية على الأدوار: لا يستطيع أحد منح دور منصة أو سحبه أو رفعه فوق صلاحياته، فلا تؤدي admins.assign_roles أو roles.assign_permissions وحدها إلى دور مسؤول المنصة.

صلاحيات المنصة الـ 21 هي platform.view وreports.export وorganizations.view وorganizations.manage وusers.view وusers.create وusers.update وusers.delete وusers.restore وadmins.view وadmins.create وadmins.edit وadmins.delete وadmins.assign_roles وroles.view وroles.create وroles.edit وroles.delete وroles.assign_permissions وsettings.view وsettings.edit.

الإعدادات العامة ووضع الصيانة

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/public-settingsأي شخصmaintenanceMode وtrialDays (قيمة trial_days للمنصة، و14 إذا لم تُضبط): ما تذكره التهيئة على أنه مدة الفترة التجريبية، وهل تعرض لوحة التحكم شاشة الصيانة. مفتوح أثناء الصيانة

ما دام إعداد المنصة maintenance_mode بقيمة true، يُجاب كل طلب من أي شخص ليس من طاقم المنصة (حساب يملك platform.view) بـ 503، مع code: "maintenance_mode" والرسالة «المنصة مغلقة مؤقتًا للصيانة. يُرجى المحاولة مرة أخرى بعد قليل.» والرمز المفقود أو الخاطئ يحصل على 503 نفسها. وتبقى هذه مفتوحة للجميع:

  • GET /api/health وGET /api/public-settings؛
  • POST /api/auth/login وPOST /api/auth/logout، حيث يرفض تسجيل الدخول أي شخص ليس من الطاقم بـ 503 حتى بعد صحة بيانات الدخول؛
  • POST /api/billing/webhooks/stripe وتنزيل الفاتورة الموقّع؛
  • نقطة MCP، التي تحتفظ بمفتاحها الخاص، وGET /api/demo/status؛
  • POST /api/contact الخاص بالموقع وكل مسار /api/licenses، فيستمر نموذج التواصل والدفع لشراء التراخيص في العمل.

كل ما عدا ذلك مغلق أمام من ليس من الطاقم، بما فيه التسجيل واستعادة الحساب والدعوات والتهيئة وواجهة API العامة تحت /api/v1 والملفات المرفوعة والمساعد. والقائمة في back-end/src/common/constants/maintenance.constants.ts.

نموذج التواصل

الطريقةالمسارمن يحق له استدعاؤهوظيفته
POST/api/contactأي شخصname (من 2 إلى 120) وemail وtopic (licensing وsetup وproduct) وmessage (من 20 إلى 4000 حرف) وclientToken (من 8 إلى 64 من الأحرف والأرقام و_ أو -) والحقل المخفي website. يجيب بـ { id }
  • clientToken المكرر يعيد معرّف الرسالة الأولى بدلًا من تخزين ثانية، فإعادة المحاولة آمنة.
  • الحقل website المملوء يُعامل على أنه روبوت: تبدو الإجابة نفسها، ولا يُخزَّن شيء.
  • يستطيع كل عنوان إرسال خمس رسائل في الساعة؛ والتالية تُجاب بـ 429.
  • تُخزَّن الرسائل في جدول contact_messages وتُحوَّل إلى CONTACT_INBOX إذا كان مضبوطًا.

الدفع بالترخيص

الطريقةالمسارمن يحق له استدعاؤهوظيفته
GET/api/licenses/checkout/optionsأي شخصوسائل الدفع (card وpaypal)، وprovider الذي يتولى كل واحدة (stripe أو paypal أو simulator)، وtestMode، وقيمته true عندما لا يحرّك أي منهما مالًا حقيقيًا
POST/api/licenses/checkoutأي شخصlicense (single وstudio) وemail وname (من 2 إلى 120) وmethod (card وpaypal)، وlocale اختياريًا (en وar)، وclientToken. يجيب بـ order، معرّف الطلب، وurl، صفحة الدفع. وصفحة الدفع التي لا تُفتح تُجاب بـ 503 مع payment_unavailable
GET/api/licenses/orders/:idأي شخص يملك معرّف الطلبالطلب: المرجع والترخيص والمبلغ والبريد والاسم والوسيلة والمزود، وstatus (pending وpaid وcancelled وfailed) وtest، وlicenseKey بعد أن يُدفع
POST/api/licenses/orders/:id/confirmأي شخص يملك معرّف الطلبعاد المشتري من Stripe أو PayPal: يُسأل المزود هل تمت الدفعة، ثم يُجاب بالطلب
POST/api/licenses/orders/:id/cancelأي شخص يملك معرّف الطلبغادر المشتري صفحة الدفع دون أن يدفع
POST/api/licenses/orders/:id/simulateأي شخص يملك معرّف الطلبزر الدفع أو الإلغاء في الدفع التجريبي: outcome (pay وcancel). الطلب الذي تولاه Stripe أو PayPal يُجاب بـ 404
  • السعر هو سعر الخادم نفسه، من back-end/src/modules/licenses/constants/license-offers.ts؛ ولا يرسل المتصفح سعرًا أبدًا.
  • تذهب البطاقة إلى Stripe Checkout عندما يكون STRIPE_SECRET_KEY مضبوطًا، وPayPal إلى PayPal عندما يكون PAYPAL_CLIENT_ID وPAYPAL_CLIENT_SECRET مضبوطين، وكلتاهما إلى الدفع التجريبي في غير ذلك. وفي الوضع التجريبي لا يُعرض أبدًا مزود بمفاتيح حقيقية.
  • يُدفع الطلب مرة واحدة، بأيٍّ يأتي أولًا من checkout.session.completed في Stripe على POST /api/billing/webhooks/stripe، أو confirm عند العودة، أو زر الدفع في الدفع التجريبي. وهذا وحده يصدر مفتاح الترخيص ويرسل الإيصال بالبريد. أما checkout.session.expired فيعلّم الطلب بأنه فاشل.
  • معرّف الطلب سلسلة عشوائية طويلة تحملها روابط عودة المشتري فقط. clientToken المكرر يُجاب بالطلب الأول. يستطيع كل عنوان بدء عشرة طلبات في الساعة.

الملفات المرفوعة والوسائط

الطريقةالمسارمن يحق له استدعاؤهوظيفته
POST/api/helpers/uploadأي حساب مسجّل الدخولتخزين صورة: file بصيغة multipart (10 ميغابايت على الأكثر)، وpath للمجلد، وfor للمقاس المعدّ مسبقًا (profile أو cover أو logo أو default). يجيب بالعناوين بحسب المقاس: original، بعرض لا يتجاوز 1920 بكسل، ونسخة واحدة مصغّرة، كلها JPEG. الملف الذي ليس صورة مقروءة يُجاب بـ 400

تذهب الصور وملفات المشاريع إلى حاوية Cloudflare R2 عندما تُضبط متغيراتها الخمسة R2_*، وإلى MEDIA_UPLOAD_DIR في غير ذلك، وتُقدَّم على PUBLIC_MEDIA_URL متبوعًا بـ /uploads/….

كل ما تقدمه واجهة API تحت /media يحمل X-Content-Type-Options: nosniff، والملف الذي ليس صورة نقطية أو PDF أو نصًا عاديًا أو صوتًا أو فيديو (مثل ملف HTML أو SVG) يُرسل مع Content-Disposition: attachment، فيُنزَّل بدلًا من أن يُفتح صفحةً على عنوان واجهة API. أما الملفات في حاوية R2 فتقدمها الحاوية، بالنوع الذي رُفعت به.

الحدود لكل عنوان

المسارالحدالمتغير
POST /api/auth/login10 محاولات دخول فاشلة كل 15 دقيقةRATE_LIMIT_LOGIN
POST /api/auth/signup10 في الساعةلا شيء
POST /api/auth/forgot-password5 كل 15 دقيقةلا شيء
POST /api/auth/reset-password10 كل 15 دقيقةلا شيء
POST /api/contact5 في الساعةلا شيء
POST /api/licenses/checkout10 في الساعةلا شيء
POST …/invitations/:id/resendمرة في الدقيقة، وخمس مرات لكل دعوةلا شيء

الطلب الذي يتجاوز حدًّا يُجاب بـ 429، مع جملة تذكر ما حُدّ وكم يجب الانتظار، مثل «طلبات تسجيل كثيرة من هذا العنوان. انتظر ساعة ثم حاول مرة أخرى.» تعيش العدادات في ذاكرة واجهة API، فيمحوها إعادة التشغيل. خلف وكيل عكسي، اضبط TRUST_PROXY على عدد الوكلاء أمام واجهة API، وإلا يُحتسب كل زائر على أنه عنوان الوكيل الواحد.

المساعد الذكي ومحادثاته واقتراحاته

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

مسار البث للمساعد، وقائمة نماذجه، والمحادثات المحفوظة، واقتراحات المهام.

خادم MCP

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

نقطة MCP لوكلاء البرمجة، وكيف يُصرَّح لها، وأي مساحة عمل تقرؤها.

تحديثات الصلاحيات الحية عبر socket.io

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

فضاء أسماء socket.io الذي تستمع إليه لوحة التحكم، وحدثه، وكيف يُصرَّح للاتصال.

مسارات وضع العرض التجريبي

مُضمَّن مع مشترياتك. سجّل الدخول لقراءته، أو افتحه في ملف التنزيل.

المسارات الموجودة فقط لبناء العرض التجريبي العام.

توقفت عند خطوة؟

ابحث عن الحل قبل أن تبدأ من جديد.

حل المشكلات

تفضيلات ملفات تعريف الارتباط

نستخدم ملفات تعريف الارتباط لتعزيز تجربة التصفح الخاصة بك وتحليل حركة المرور على الموقع وتخصيص المحتوى. بالنقر على "قبول الكل"، فإنك توافق على استخدامنا لملفات تعريف الارتباط للتحليلات والإعلانات المخصصة.