Timmy Device Manager — API Reference

This page documents the backend HTTP APIs and example cURL requests. All authenticated endpoints require Authorization: Bearer <JWT>.

How to get a token (Login)
Use this endpoint to obtain JWT used in subsequent requests.
POST /api/auth/login — public
Request body (JSON)
{
  "email": "admin@timmy.local",
  "password": "admin123"
}
cURL
curl -s -X POST http://localhost:9090/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"admin@timmy.local","password":"admin123"}'
Successful response
{
  "success": true,
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "user": { "email":"admin@timmy.local","name":"Admin","role":"ADMIN" }
}
Queue / Operation model (general)
The system records every device-related action as an Operation document in MongoDB. Typical operation fields:
{
  "_id": "64f5...abc",
  "sn": "ZXRE06022863",
  "type": "setuserinfo",         // command name sent to device
  "payload": { ... },            // original payload sent
  "response": { ... },           // device response (if any)
  "status": "pending|sent|success|failed|canceled",
  "attemptCount": 0,
  "lastError": "...",
  "createdAt": "2025-11-08T10:00:00.000Z"
}
When using the documented endpoints that send commands, you'll receive a JSON with at minimum success and an op object or queued/ note describing the result.
Operations listing (filtering & paging)
List stored operation records with filters, date range and paging.
GET /api/operations — auth required
Query parameters
page=1           // default
limit=20         // default
sn=ZXRE06022863  // optional
type=setuserinfo // optional
status=failed    // optional
from=YYYY-MM-DD  // optional (createdAt >= from)
to=YYYY-MM-DD    // optional (createdAt <= to)
    
cURL
curl -s "http://localhost:9090/api/operations?page=1&limit=20&sn=ZXRE06022863&from=2025-11-01&to=2025-11-10" \
  -H "Authorization: Bearer $TOKEN"
Example Response
{
  "success": true,
  "total": 123,
  "page": 1,
  "items": [
    {
      "_id": "...",
      "sn": "ZXRE06022863",
      "type": "setuserinfo",
      "payload": { ... },
      "response": { ... },
      "status": "success",
      "attemptCount": 1,
      "createdAt": "2025-11-08T10:00:00.000Z"
    },
    ...
  ]
}
Operation actions: Cancel / Retry
Cancel or request immediate retry for a recorded operation.
POST /api/operations/:id/cancel — auth required
curl -s -X POST http://localhost:9090/api/operations/64f5...abc/cancel \
  -H "Authorization: Bearer $TOKEN"
Response (example)
{
  "success": true,
  "op": { "_id":"64f5...abc", "status":"canceled", ... }
}
POST /api/operations/:id/retry — auth required
curl -s -X POST http://localhost:9090/api/operations/64f5...abc/retry \
  -H "Authorization: Bearer $TOKEN"
Response (example)
{
  "success": true,
  "queued": true,
  "op": { "_id":"64f5...abc", "status":"pending", "attemptCount": 2 }
}
Stats
Aggregate counts by status / type
GET /api/stats — auth required
curl -s http://localhost:9090/api/stats -H "Authorization: Bearer $TOKEN"
Example response
{
  "success": true,
  "total": 123,
  "byStatus": [{ "_id":"success","count":80 }, { "_id":"failed","count":20 }, ...],
  "byType": [{ "_id":"setuserinfo","count":90 }, ...]
}
Device users (read full list)
Ask the device for full users list (this creates an operation record and communicates with the device).
GET /api/device/:sn/users — auth required
curl -s http://localhost:9090/api/device/ZXRE06022863/users \
  -H "Authorization: Bearer $TOKEN"
Success response (device must be online)
{
  "success": true,
  "records": [
    { "enrollid": 1, "name":"John", "aliasid":"J1", "backupnum":50, "record":"..." },
    { "enrollid": 2, "name":"Sally", "backupnum":2, "template":"..." }
  ],
  "raw": { /* raw device response object */ }
}
If the device is offline, you'll receive: {success:false, error:'device_offline_or_not_registered'}
Bulk delete users on a device
Delete multiple enroll IDs from a single device (creates operations for each delete)
POST /api/device/:sn/delete-users — auth required
Request body
{
  "enrollIds": [2,3,15]
}
cURL
curl -s -X POST http://localhost:9090/api/device/ZXRE06022863/delete-users \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"enrollIds":[2,3,15]}'
Response (example)
{
  "success": true,
  "sn": "ZXRE06022863",
  "count": 3,
  "results": [
    { "enrollid": 2, "opId":"64f...", "status":"pending" },
    { "enrollid": 3, "opId":"650...", "status":"pending" }
  ]
}
Transfer / Copy users (device → device)
Copy or move (copy + delete from source) users from one device to another. The endpoint will create multiple sub-operations: fetch user backup blocks from source, push to target, optionally delete on source.
POST /api/transfer-users — auth required
Request body
{
  "fromSn": "ZXRE06022863",
  "toSn": "TYSG18086518",
  "enrollIds": [2,3],          // optional: if absent => transfer all users
  "deleteFromSource": false    // true = move, false = copy
}
cURL
curl -s -X POST http://localhost:9090/api/transfer-users \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fromSn":"ZXRE06022863","toSn":"TYSG18086518","enrollIds":[2,3],"deleteFromSource":true}'
Example response
{
  "success": true,
  "fromSn": "ZXRE06022863",
  "toSn": "TYSG18086518",
  "results": [
    {
      "enrollid": 2,
      "steps": [
        { "backupnum": 50, "action":"fetch", "result":"success" },
        { "backupnum": 50, "action":"push", "opId":"64f...", "result":"pending" },
        { "action":"delete_from_source", "opId":"650...", "result":"pending" }
      ]
    }
  ]
}
Add new user to a device
This endpoint sends an adduserinfo command to a connected device to register a new user (fingerprint or face). The device must be online.

No record field is required — the device will create the biometric template internally.
Use backupnum to indicate the biometric type:
  • backupnum = 0 → Fingerprint user
  • backupnum = 50 → Face user
POST /api/device/:sn/add-user — auth required
Request body (JSON)
{
  "enrollid": 10012,
  "name": "John Smith1",
  "aliasid": "JSMITH1",
  "backupnum": 50
}
Example cURL
curl -s -X POST http://localhost:9090/api/device/ZXRE06022863/add-user \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enrollid": 10012,
    "name": "John Smith1",
    "aliasid": "JSMITH1",
    "backupnum": 50
  }'
Successful response (example)
{
  "success": true,
  "opId": "673bd98fa14b34d6c9db2009",
  "status": "success",
  "response": {
    "ret": "adduser",
    "result": true
  }
}
If the device is offline you'll receive { "success": false, "error": "device_offline_or_not_registered" }. Each request is logged as an Operation document of type adduserinfo.
Clean all logs from a device
Sends the cleanlog command to a connected device to erase all attendance records stored locally on that device. The device must be online.
POST /api/device/:sn/clean-log — auth required
No request body is needed.
Example cURL
curl -s -X POST http://localhost:9090/api/device/ZXRE06022863/clean-log \
  -H "Authorization: Bearer $TOKEN"
Response (example)
{
  "success": true,
  "opId": "673bd98fa14b34d6c9db2009",
  "status": "success",
  "response": {
    "ret": "cleanlog",
    "result": true
  }
}
A corresponding Operation entry of type cleanlog is recorded in MongoDB for audit tracking.
Forward device logs (optional)
Devices can forward logs to your server via /api/device-log. The server will attempt to forward these logs to configured FORWARD_LOG_URL.
POST /api/device-log
curl -s -X POST http://localhost:9090/api/device-log \
  -H "Content-Type: application/json" \
  -d '{"sn":"ZXRE06022863","record":[ { "enrollid":2, "time":"2025-11-08T09:00:00" } ] }'
Response
{
  "success": true,
  "forwarded": false,
  "retryLater": true
}

Employee APIs (login & management)
These endpoints manage employees used by the mobile app. Admins can create/edit employees; employees can log in with their username/password.
POST /api/employees/login — public
Request body (JSON)
{
  "username": "emp-86359.mo",
  "password": "password123"
}
cURL
curl -s -X POST http://localhost:9090/api/employees/login \
  -H "Content-Type: application/json" \
  -d '{"username":"emp-86359.mo","password":"password123"}'
Example response
{
  "message": "Login successful",
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6...",
  "result": {
    "_id": "692553de39586fb9c712e3cd",
    "enroll_id": "86359",
    "name": "Employee Name",
    "username": "emp-86359.mo",
    "owner": "679a312fba856722da62098d",
    "app_permissions": {
      "can_login_app": true,
      "can_view_fingerprint": true,
      "...": false
    },
    "...": "... other fields ..."
  }
}

GET /api/employees — auth (admin)
List employees for the current owner with optional search.
Query parameters
q=...   // optional text filter on username / fullName / phone / email
cURL
curl -s "http://localhost:9090/api/employees?q=mustafa" \
  -H "Authorization: Bearer $TOKEN"
Response (example)
{
  "success": true,
  "items": [
    {
      "_id": "69256416bd792a2ff963a6c9",
      "enroll_id": "121",
      "username": "asd",
      "fullName": "mustafa",
      "phone": "",
      "email": "",
      "isActive": true,
      "owner": "690f78b6dcccc75fb6722fe2",
      "createdAt": "2025-11-25T..."
    }
  ]
}

POST /api/employees — auth (admin)
Create a new employee (used by the mobile app).
Request body
{
  "enroll_id": "121",
  "username": "asd",
  "password": "strongPassword",
  "fullName": "mustafa",
  "phone": "0770xxxxxxx",
  "email": "mustafa@example.com"
}
cURL
curl -s -X POST http://localhost:9090/api/employees \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enroll_id":"121",
    "username":"asd",
    "password":"strongPassword",
    "fullName":"mustafa"
  }'

PUT /api/employees/:id — auth (admin)
Update existing employee (partial update).
curl -s -X PUT http://localhost:9090/api/employees/69256416bd792a2ff963a6c9 \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"fullName":"Mustafa Updated","phone":"0770xxxxxxx"}'

DELETE /api/employees/:id — auth (admin)
curl -s -X DELETE http://localhost:9090/api/employees/69256416bd792a2ff963a6c9 \
  -H "Authorization: Bearer $TOKEN"
Mobile fingerprints — create & forward to 2nd server
These endpoints handle attendance logs coming from the mobile app, store them as FingerPrintLog documents, and optionally forward them to a second server (e.g. /api/checkinout/save).
POST /api/fingerprints/app — auth (employee)
Create a fingerprint log from the mobile app and forward to the client server.
Request body
{
  "event": 1,
  "location": {
    "latitude": 33.3096307,
    "longitude": 44.4490251
  },
  "device_sn": "App",
  "device_name": "App",
  "macs": "aa:bb:cc:dd:ee:ff",
  "image": "data:image/jpeg;base64,... (optional)"
}
cURL (employee JWT token)
curl -s -X POST http://localhost:9090/api/fingerprints/app \
  -H "Authorization: Bearer $EMPLOYEE_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "event": 1,
    "location": { "latitude":33.30963, "longitude":44.44902 },
    "device_sn": "App",
    "device_name": "App",
    "macs": "aa:bb:cc:dd:ee:ff"
  }'
Response (example)
{
  "success": true,
  "message": "تم تسجيل بصمة الموبايل بنجاح",
  "data": {
    "_id": "6925d3b4c8227c3a1972328b",
    "enrollid": "121",
    "event": 1,
    "time": "2025-11-25T16:05:08.665Z",
    "device_sn": "App",
    "device_type": "mobile_app",
    "is_send": true,
    "send_failed": false,
    "forwardedAt": "2025-11-25T16:05:09.000Z",
    "forwardResponse": { "success": true, "forwarded": true },
    "...": "..."
  },
  "forwarded": true
}
Forward URL and token are configured via FORWARD_FINGERPRINT_URL / FORWARD_LOG_URL and FORWARD_FINGERPRINT_TOKEN / FORWARD_LOG_TOKEN in .env. The payload forwarded to the client looks like:
{
  "sn": "App",
  "record": [
    {
      "enrollid": 121,
      "time": "2025-11-25T16:05:08.665Z",
      "event": 1
    }
  ]
}
Mobile fingerprints — listing (employee & admin)
Employee endpoints return their own logs, while admin endpoints list all mobile logs with filters and pagination.
GET /api/fingerprints/employee — auth (employee)
List fingerprint logs for the current employee.
Query parameters (all optional)
from=ISO8601      // filter by time >= from
to=ISO8601        // filter by time <= to
event=1           // filter by event code
device_sn=App     // filter by device
page=1            // default
limit=10          // default
is_send=true|false
    
cURL
curl -s "http://localhost:9090/api/fingerprints/employee?from=2025-02-01T00:00:00.000Z&to=2025-02-05T23:59:59.000Z&page=1&limit=20" \
  -H "Authorization: Bearer $EMPLOYEE_TOKEN"
Response (example)
{
  "logs": [
    {
      "_id": "6925d3b4c8227c3a1972328b",
      "enrollid": "121",
      "event": 1,
      "time": "2025-11-25T16:05:08.665Z",
      "device_sn": "App",
      "is_send": true,
      "send_failed": false,
      "forwardedAt": "2025-11-25T16:05:09.000Z"
    }
  ],
  "totalCount": 1,
  "currentPage": 1,
  "limit": 20,
  "totalPages": 1
}

GET /api/fingerprints/mobile-logs — auth (admin)
List all mobile-app logs (device_type = "mobile_app") with filters and pagination.
Query parameters
page=1
limit=20
from=ISO8601
to=ISO8601
is_send=true|false
send_failed=true|false
    
cURL
curl -s "http://localhost:9090/api/fingerprints/mobile-logs?page=1&limit=20&send_failed=true" \
  -H "Authorization: Bearer $TOKEN"
Response (example)
{
  "success": true,
  "items": [
    {
      "_id": "6925d3b4c8227c3a1972328b",
      "enrollid": "121",
      "name": "mustafa",
      "event": 1,
      "time": "2025-11-25T16:05:08.665Z",
      "device_sn": "App",
      "is_send": true,
      "send_failed": false,
      "forwardedAt": "2025-11-25T16:05:09.000Z",
      "forwardResponse": { "success": true, "forwarded": true }
    }
  ],
  "totalCount": 1,
  "currentPage": 1,
  "limit": 20,
  "totalPages": 1
}
Mobile fingerprints — retry forwarding failed & pending
This endpoint retries forwarding all mobile-app fingerprints that either failed to send or are still pending (is_send = false).
POST /api/fingerprints/retry-failed — auth (admin)
Request body
{}
cURL
curl -s -X POST http://localhost:9090/api/fingerprints/retry-failed \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{}'
Behavior
- Selects logs where:
  device_type = "mobile_app" AND
  ( (is_send = true AND send_failed = true) OR (is_send = false) )

- For each log:
  → Sends payload:
     { "sn": log.device_sn || "App",
       "record": [ { "enrollid", "time", "event" } ] }
  → Updates:
     is_send = true
     send_failed = !ok
     forwardResponse, forwardedAt, last_attempt_error
    
Response (example)
{
  "success": true,
  "message": "Retry finished",
  "count": 5,
  "successCount": 4,
  "failedCount": 1,
  "results": [
    { "id": "6925d3b4c8227c3a1972328b", "ok": true,  "response": { "success": true, "forwarded": true } },
    { "id": "6925d3b4c8227c3a1972328c", "ok": false, "error": "Remote server did not confirm receipt" }
  ]
}

Contact & Notes
- The examples assume HTTP server on http://localhost:9090 and WebSocket port on ws://localhost:9091.
- Replace $TOKEN with the admin JWT returned by login, and $EMPLOYEE_TOKEN with the employee JWT.
- The Operation model is central; storing payload + response enables auditing, retries, and manual replays.
- Mobile fingerprints are stored in FingerPrintLog and can be forwarded to external HR/attendance systems.