→ العودة إلى لوحة التحكم

📘 دليل ربط API — منصّة البصمات

💡 اكتب رابطك وتوكنك هنا فتتحدّث كل الأمثلة في الصفحة تلقائياً وتصبح جاهزة للنسخ.

١. مقدمة وبداية سريعة

تتيح هذه البوابة لنظامك سحب بيانات الحضور/البصمات الخاصة بمؤسستك وإدارة أجهزتها، عبر توكن واحد خاص بمؤسستك. كل طلب يُحدِّد مؤسستك تلقائياً — لن ترى إلا بياناتك.

كل المسارات تبدأ بـ /api/v1. أول تجربة — تحقّق من توكنك:

curl -H "Authorization: Bearer __TOKEN__" \
  __BASE__/api/v1/me

إن رجع "ok": true ومعلومات مؤسستك فالتوكن يعمل.

٢. المصادقة

أرسل التوكن في ترويسة Authorization مع كل طلب:

Authorization: Bearer __TOKEN__
🔒 التوكن يُعرض مرة واحدة عند إنشائه. إذا تسرّب، دوّره من لوحة التحكم (صفحة «المؤسسات») — يبطل القديم فوراً.

٣. سحب البيانات (قراءة)

GET/api/v1/me

معلومات مؤسستك + أعداد الأجهزة والطلاب.

curl -H "Authorization: Bearer __TOKEN__" __BASE__/api/v1/me
GET/api/v1/devices

أجهزتك وحالة اتصالها الآن (online حيّ، وليس قيمة قديمة).

curl -H "Authorization: Bearer __TOKEN__" __BASE__/api/v1/devices
GET/api/v1/students

الطلاب/الموظفون المسجّلون على أجهزتك (الرقم والاسم).

curl -H "Authorization: Bearer __TOKEN__" __BASE__/api/v1/students
GET/api/v1/attendance

سجلات الحضور/البصمات (الأحدث أولاً) مع ترقيم بالمؤشّر (cursor).

المعاملالوصف
limitعدد السجلات (١–٥٠٠، الافتراضي ١٠٠)
sinceمن تاريخ (ISO مثل 2026-06-23T00:00:00Z)
untilإلى تاريخ (ISO)
cursorمؤشّر الصفحة التالية (من nextCursor)
curl -H "Authorization: Bearer __TOKEN__" \
  "__BASE__/api/v1/attendance?limit=100"

مثال الرد:

{
  "ok": true,
  "attendance": [
    {
      "sn": "STC010083287",
      "enrollid": 1,
      "name": "علي رياض",
      "time": "2026-06-19 14:51:06",
      "eventAt": "2026-06-19T11:51:06.000Z",
      "inout": 0,
      "mode": 8,
      "imageUrl": "/images/..._.jpg",
      "createdAt": "2026-06-19T11:51:07.000Z"
    }
  ],
  "hasMore": true,
  "nextCursor": "eyJ0Ijox..."
}

inout: 0 = دخول، 1 = خروج · mode: 8/15 = وجه، 0/1 = بصمة إصبع.

٤. إدارة الأجهزة

أوامر تُرسَل للجهاز وتُرجع فوراً 202 مع commandId (لا تنتظر رد الجهاز). يجب أن يكون الجهاز متّصلاً (وإلا 409).

POST/api/v1/devices/:sn/users

تسجيل/تعديل مستخدم على الجهاز. backupnum: 0–9 بصمة · 10 كلمة مرور · 11 بطاقة · 20–27 وجه · 50 صورة وجه.

curl -X POST "__BASE__/api/v1/devices/STC010083287/users" \
  -H "Authorization: Bearer __TOKEN__" \
  -H "content-type: application/json" \
  -d '{"enrollid":20,"name":"طالب جديد","backupnum":0}'
DELETE/api/v1/devices/:sn/users/:enrollid

حذف مستخدم. أضف ?backupnum= لحذف قالب محدّد (الافتراضي: الكل).

curl -X DELETE "__BASE__/api/v1/devices/STC010083287/users/20" \
  -H "Authorization: Bearer __TOKEN__"
POST/api/v1/devices/:sn/open-door

فتح الباب (لأجهزة التحكم بالدخول). الجسم اختياري: {"doornum":1}.

curl -X POST "__BASE__/api/v1/devices/STC010083287/open-door" \
  -H "Authorization: Bearer __TOKEN__" -H "content-type: application/json" -d '{}'
POST/api/v1/devices/:sn/sync

سحب فوري من الجهاز. what: newlog (سجلات جديدة) أو userlist (المستخدمون) أو both.

curl -X POST "__BASE__/api/v1/devices/STC010083287/sync" \
  -H "Authorization: Bearer __TOKEN__" -H "content-type: application/json" \
  -d '{"what":"both"}'

٥. البث اللحظي (Real-time stream)

بدل السحب المتكرر، افتح اتصال WebSocket واحد فيصلك كل حضور لحظة حدوثه — معزولاً لمؤسستك فقط (توكنك يحدّد مؤسستك، ولا ترى أحداث غيرها).

WS/api/v1/stream

المصادقة بترويسة Authorization: Bearer (للخوادم) أو ?token= (للمتصفح، لأنه لا يدعم ترويسات في WebSocket).

أنواع الأحداث الواردة:

{ "type": "connected", "institution": { "id": "...", "name": "...", "slug": "..." } }

{ "type": "attendance", "sn": "STC010083287", "enrollid": 1, "name": "علي رياض",
  "time": "2026-06-19 14:51:06", "inout": 0, "mode": 8, "at": "2026-06-19T11:51:07.000Z" }

{ "type": "device", "sn": "STC010083287", "online": true, "at": "..." }

Node.js (خادم — بترويسة Authorization)

const WebSocket = require("ws");

function connect() {
  const ws = new WebSocket("__WSBASE__/api/v1/stream", {
    headers: { Authorization: "Bearer __TOKEN__" }
  });
  ws.on("message", (raw) => {
    const ev = JSON.parse(raw);
    if (ev.type === "attendance")
      console.log("حضور:", ev.enrollid, ev.name, ev.time, ev.inout ? "خروج" : "دخول");
  });
  ws.on("close", () => setTimeout(connect, 3000)); // أعد الاتصال تلقائياً
  ws.on("error", () => {});
}
connect();

المتصفح (التوكن في الرابط)

const ws = new WebSocket("__WSBASE__/api/v1/stream?token=__TOKEN__");
ws.onmessage = (e) => {
  const ev = JSON.parse(e.data);
  if (ev.type === "attendance") console.log("حضور:", ev.name, ev.time);
};
💓 يرسل الخادم نبضة (ping) كل ٣٠ ثانية للحفاظ على الاتصال. عالج الانقطاع بإعادة اتصال تلقائية كما في مثال Node أعلاه. توكن خاطئ → يُرفض الاتصال بـ 401.

٦. سحب الحضور تدريجياً (المؤشّر)

لجلب الجديد فقط في كل مرة: استخدم nextCursor من الرد السابق كـ cursor للطلب التالي، ودُر طالما hasMore = true. احفظ آخر مؤشّر لتبدأ منه لاحقاً.

⚠️ إذا تعطّلت القاعدة مؤقتاً، تُعاد بعض البصمات لاحقاً بترتيب وصول مختلف. للضمان: أعد المسح دورياً من since أقدم بقليل، أو طابِق السجلات بمفتاح enrollid + time.

٧. أمثلة تكامل بلغات مختلفة

سحب كل الحضور صفحةً صفحة:

const BASE = "__BASE__";
const TOKEN = "__TOKEN__";

async function pullAll(cursor) {
  let url = `${BASE}/api/v1/attendance?limit=200`;
  if (cursor) url += `&cursor=${encodeURIComponent(cursor)}`;
  const res = await fetch(url, { headers: { Authorization: `Bearer ${TOKEN}` } });
  const data = await res.json();
  for (const rec of data.attendance) {
    // خزّن rec في نظامك — المفتاح الفريد: enrollid + time
    console.log(rec.enrollid, rec.name, rec.time);
  }
  if (data.hasMore) return pullAll(data.nextCursor);
  return data.nextCursor; // احفظه لتبدأ منه لاحقاً
}
pullAll();
<?php
$BASE  = "__BASE__";
$TOKEN = "__TOKEN__";

function pull($BASE, $TOKEN, $cursor = null) {
  $url = "$BASE/api/v1/attendance?limit=200";
  if ($cursor) $url .= "&cursor=" . urlencode($cursor);
  $ch = curl_init($url);
  curl_setopt($ch, CURLOPT_HTTPHEADER, ["Authorization: Bearer $TOKEN"]);
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  $data = json_decode(curl_exec($ch), true);
  curl_close($ch);
  foreach ($data["attendance"] as $rec) {
    // خزّن $rec في نظامك (enrollid + time مفتاح فريد)
  }
  if (!empty($data["hasMore"])) return pull($BASE, $TOKEN, $data["nextCursor"]);
  return $data["nextCursor"];
}
pull($BASE, $TOKEN);
import requests

BASE  = "__BASE__"
TOKEN = "__TOKEN__"
H = {"Authorization": f"Bearer {TOKEN}"}

def pull(cursor=None):
    params = {"limit": 200}
    if cursor: params["cursor"] = cursor
    data = requests.get(f"{BASE}/api/v1/attendance", headers=H, params=params).json()
    for rec in data["attendance"]:
        print(rec["enrollid"], rec["name"], rec["time"])  # خزّنه في نظامك
    if data.get("hasMore"):
        return pull(data["nextCursor"])
    return data.get("nextCursor")

pull()

٨. الأخطاء والحدود

كل الأخطاء بالشكل: {"ok": false, "error": "...", "message": "..."}

الكودالمعنى
400معامل ناقص أو غير صالح
401توكن ناقص أو خاطئ
404الجهاز غير موجود أو ليس ملكاً لمؤسستك
409device_offline — الجهاز غير متصل الآن
429تجاوزت حد الطلبات
202أمر الإدارة قُبل وأُرسل للجهاز

الحدود: القراءة ١٢٠ طلب/دقيقة · الإدارة ٣٠ طلب/دقيقة لكل توكن.

٩. ملاحظات مهمة

  • العزل مضمون: توكنك يرى بيانات مؤسستك فقط.
  • عدّة أجهزة: كل أجهزة مؤسستك تعمل بنفس التوكن.
  • الصور: imageUrl مرجعي فقط، لا يُجلب عبر هذه البوابة في الإصدار الحالي.
  • المفتاح الفريد للسجل: sn + enrollid + time (قد تتكرر بصمتان في نفس الثانية بمؤشّر مختلف).
  • استخدم HTTPS دائماً في الإنتاج.