Comprehensive API documentation for Biometric Attendance System Integration
Version 1.0 | Last Updated: October 10, 2025
This API provides a simple and efficient way to integrate biometric attendance systems with your workforce management platform. The system stores attendance records and provides endpoints for submitting and querying attendance data.
https://api.clms.co.tz/api/All API endpoints are publicly accessible and do not require authentication. You can access any endpoint directly without API keys or authentication headers.
Since authentication has been removed, consider implementing server-level security for production deployments:
Description: Check API health status and basic statistics
Authentication: Not required
{
"success": true,
"message": "API is operational",
"data": {
"api_status": "online",
"database_status": "connected",
"api_version": "1.0",
"timezone": "Africa/Dar_es_Salaam",
"server_time": "2025-10-10 14:30:00",
"statistics": {
"total_workers": 35,
"total_attendance_records": 1245,
"today_attendance": 28
}
},
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0"
}
Description: Submit attendance data from biometric system. Supports both single record and bulk submission formats.
Authentication: Not required
The API accepts biometric system format with automatic field mapping:
{
"biometricData": [
{
"status": 300,
"datetime": "2025-09-15T12:40:00Z",
"employeeIDNumber": "W00065",
"biometricName": "Gate 7/8",
"scanId": "SCAN-ID-493"
},
{
"status": 300,
"datetime": "2025-09-15T12:45:00Z",
"employeeIDNumber": "W00062",
"biometricName": "Gate 7/8",
"scanId": "SCAN-ID-473"
}
]
}
| Parameter | Type | Required | Description |
|---|---|---|---|
biometricData |
array | Required | Array of biometric records |
biometricData[].employeeIDNumber |
string | Required | Worker's unique ID (mapped to worker_id) |
biometricData[].datetime |
datetime | Required | Check-in timestamp in ISO 8601 format (e.g., "2025-09-15T12:40:00Z") |
biometricData[].biometricName |
string | Optional | Location/device name (mapped to check_in_location and biometric_device_id) |
biometricData[].scanId |
string | Optional | Scan identifier (stored in remarks field) |
biometricData[].status |
integer | Optional | Status code: 300=present, 400=late, 500=absent, 600=on_leave (default: 300) |
{
"status": "success",
"message": "Successfully processed 2 biometric records",
"data": {
"processed": 2,
"successful": 2,
"failed": 0
}
}
{
"status": "success",
"message": "Successfully processed 2 biometric records",
"data": {
"processed": 3,
"successful": 2,
"failed": 1,
"failed_records": [
{
"index": 1,
"record": { ... },
"error": "Worker not found",
"details": {
"worker_id": "W00062"
}
}
]
}
}
employeeIDNumber → worker_iddatetime (ISO 8601) → check_in (converted to Y-m-d H:i:s)biometricName → check_in_location and biometric_device_idscanId → stored in remarks fieldstatus (numeric) → mapped to status enumFor backward compatibility, the API still accepts single record format:
| Parameter | Type | Required | Description |
|---|---|---|---|
worker_id |
string | Required | Worker's unique ID (must exist in workers table) |
check_in |
datetime | Required | Check-in timestamp (Y-m-d H:i:s format) |
check_out |
datetime | Optional | Check-out timestamp (Y-m-d H:i:s format) |
status |
enum | Optional | Attendance status: present, absent, late, half_day, on_leave (default: present) |
biometric_device_id |
string | Optional | ID of the biometric device used |
check_in_location |
string | Optional | Location/device name for check-in |
check_out_location |
string | Optional | Location/device name for check-out |
remarks |
text | Optional | Additional notes or reasons |
{
"worker_id": "WRK20253975",
"check_in": "2025-10-10 08:30:00",
"biometric_device_id": "DEVICE_001",
"check_in_location": "Main Entrance",
"status": "present"
}
{
"success": true,
"message": "Attendance recorded successfully",
"data": {
"id": 1246,
"worker_id": "WRK20253975",
"worker_name": "Victor Sostenes Langula",
"date": "2025-10-10",
"check_in": "2025-10-10 08:30:00",
"check_out": null,
"total_hours": null,
"overtime_hours": 0,
"status": "present",
"biometric_device_id": "DEVICE_001"
},
"timestamp": "2025-10-10 08:30:15",
"api_version": "1.0"
}
{
"worker_id": "WRK20253975",
"check_in": "2025-10-10 08:30:00",
"check_out": "2025-10-10 17:45:00",
"check_out_location": "Main Entrance",
"status": "present"
}
{
"success": true,
"message": "Attendance record updated successfully",
"data": {
"id": 1246,
"worker_id": "WRK20253975",
"worker_name": "Victor Sostenes Langula",
"date": "2025-10-10",
"check_in": "2025-10-10 08:30:00",
"check_out": "2025-10-10 17:45:00",
"total_hours": 9.25,
"overtime_hours": 1.25,
"status": "present"
},
"timestamp": "2025-10-10 17:45:10",
"api_version": "1.0"
}
total_hours and overtime_hours when both check-in and check-out are provided. Standard work hours are set to 8 hours by default.
biometricData array.
Description: Query attendance records with filtering options
Authentication: Not required
| Parameter | Type | Required | Description |
|---|---|---|---|
worker_id |
string | Optional | Filter by specific worker ID |
date_from |
date | Optional | Start date (Y-m-d format) |
date_to |
date | Optional | End date (Y-m-d format) |
status |
enum | Optional | Filter by status: present, absent, late, half_day, on_leave |
page |
integer | Optional | Page number for pagination (default: 1) |
per_page |
integer | Optional | Records per page (default: 50, max: 100) |
GET /api/query-attendance.php?worker_id=WRK20253975&date_from=2025-10-01&date_to=2025-10-10&page=1&per_page=10
{
"success": true,
"message": "Attendance records retrieved successfully",
"data": [
{
"id": 1246,
"worker": {
"worker_id": "WRK20253975",
"name": "Victor Sostenes Langula",
"email": "victor.langula@gmail.com",
"phone": "0624089337"
},
"attendance": {
"date": "2025-10-10",
"check_in": "2025-10-10 08:30:00",
"check_out": "2025-10-10 17:45:00",
"total_hours": 9.25,
"overtime_hours": 1.25,
"status": "present"
},
"device_info": {
"biometric_device_id": "DEVICE_001",
"check_in_location": "Main Entrance",
"check_out_location": "Main Entrance"
},
"remarks": null,
"sync_status": "synced",
"timestamps": {
"created_at": "2025-10-10 08:30:15",
"updated_at": "2025-10-10 17:45:10"
}
}
],
"timestamp": "2025-10-10 18:00:00",
"api_version": "1.0",
"meta": {
"pagination": {
"total": 1,
"per_page": 10,
"current_page": 1,
"total_pages": 1,
"has_more": false
}
}
}
Description: Retrieve list of workers for biometric system synchronization
Authentication: Not required
| Parameter | Type | Required | Description |
|---|---|---|---|
status |
enum | Optional | Filter by status: available, busy, unavailable, banned, suspended |
page |
integer | Optional | Page number (default: 1) |
per_page |
integer | Optional | Records per page (default: 100, max: 500) |
GET /api/list-workers.php?status=available&per_page=20
{
"success": true,
"message": "Workers retrieved successfully",
"data": [
{
"id": 1,
"worker_id": "WRK20253975",
"first_name": "Victor Sostenes",
"last_name": "Langula",
"email": "victor.langula@gmail.com",
"phone": "0624089337",
"id_number": "E55454",
"availability_status": "available",
"registration_status": "approved"
}
],
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0",
"meta": {
"pagination": {
"total": 1,
"per_page": 20,
"current_page": 1,
"total_pages": 1,
"has_more": false
}
}
}
<?php
// Submit multiple attendance records
$biometricData = [
[
'status' => 300,
'datetime' => '2025-09-15T12:40:00Z',
'employeeIDNumber' => 'W00065',
'biometricName' => 'Gate 7/8',
'scanId' => 'SCAN-ID-493'
],
[
'status' => 300,
'datetime' => '2025-09-15T12:45:00Z',
'employeeIDNumber' => 'W00062',
'biometricName' => 'Gate 7/8',
'scanId' => 'SCAN-ID-473'
]
];
$payload = json_encode(['biometricData' => $biometricData]);
$ch = curl_init('https://api.clms.co.tz/api/submit-attendance.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
echo "Processed: " . $result['data']['processed'] . "\n";
echo "Successful: " . $result['data']['successful'] . "\n";
echo "Failed: " . $result['data']['failed'] . "\n";
?>
// Submit multiple attendance records
const biometricData = [
{
status: 300,
datetime: '2025-09-15T12:40:00Z',
employeeIDNumber: 'W00065',
biometricName: 'Gate 7/8',
scanId: 'SCAN-ID-493'
},
{
status: 300,
datetime: '2025-09-15T12:45:00Z',
employeeIDNumber: 'W00062',
biometricName: 'Gate 7/8',
scanId: 'SCAN-ID-473'
}
];
const response = await fetch('https://api.clms.co.tz/api/submit-attendance.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ biometricData })
});
const result = await response.json();
console.log(`Processed: ${result.data.processed}`);
console.log(`Successful: ${result.data.successful}`);
console.log(`Failed: ${result.data.failed}`);
import requests
# Submit multiple attendance records
biometric_data = [
{
'status': 300,
'datetime': '2025-09-15T12:40:00Z',
'employeeIDNumber': 'W00065',
'biometricName': 'Gate 7/8',
'scanId': 'SCAN-ID-493'
},
{
'status': 300,
'datetime': '2025-09-15T12:45:00Z',
'employeeIDNumber': 'W00062',
'biometricName': 'Gate 7/8',
'scanId': 'SCAN-ID-473'
}
]
response = requests.post(
'https://api.clms.co.tz/api/submit-attendance.php',
headers={
'Content-Type': 'application/json'
},
json={'biometricData': biometric_data}
)
result = response.json()
print(f"Processed: {result['data']['processed']}")
print(f"Successful: {result['data']['successful']}")
print(f"Failed: {result['data']['failed']}")
curl -X POST https://api.clms.co.tz/api/submit-attendance.php \
-H "Content-Type: application/json" \
-d '{
"biometricData": [
{
"status": 300,
"datetime": "2025-09-15T12:40:00Z",
"employeeIDNumber": "W00065",
"biometricName": "Gate 7/8",
"scanId": "SCAN-ID-493"
},
{
"status": 300,
"datetime": "2025-09-15T12:45:00Z",
"employeeIDNumber": "W00062",
"biometricName": "Gate 7/8",
"scanId": "SCAN-ID-473"
}
]
}'
<?php
// Submit single attendance record
$data = [
'worker_id' => 'WRK20253975',
'check_in' => '2025-10-10 08:30:00',
'biometric_device_id' => 'DEVICE_001',
'check_in_location' => 'Main Entrance',
'status' => 'present'
];
$ch = curl_init('https://api.clms.co.tz/api/submit-attendance.php');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
curl_close($ch);
$result = json_decode($response, true);
print_r($result);
?>
// Submit single attendance record
const submitAttendance = async () => {
const data = {
worker_id: 'WRK20253975',
check_in: '2025-10-10 08:30:00',
biometric_device_id: 'DEVICE_001',
check_in_location: 'Main Entrance',
status: 'present'
};
const response = await fetch('https://api.clms.co.tz/api/submit-attendance.php', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
});
const result = await response.json();
console.log(result);
};
submitAttendance();
import requests
import json
from datetime import datetime
# Submit single attendance record
url = 'https://api.clms.co.tz/api/submit-attendance.php'
headers = {
'Content-Type': 'application/json'
}
data = {
'worker_id': 'WRK20253975',
'check_in': datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
'biometric_device_id': 'DEVICE_001',
'check_in_location': 'Main Entrance',
'status': 'present'
}
response = requests.post(url, headers=headers, json=data)
result = response.json()
print(json.dumps(result, indent=2))
curl -X POST https://api.clms.co.tz/api/submit-attendance.php \
-H "Content-Type: application/json" \
-d '{
"worker_id": "WRK20253975",
"check_in": "2025-10-10 08:30:00",
"biometric_device_id": "DEVICE_001",
"check_in_location": "Main Entrance",
"status": "present"
}'
The API uses standard HTTP status codes and returns consistent error responses:
| Status Code | Meaning | Description |
|---|---|---|
200 |
OK | Request succeeded |
201 |
Created | Resource created successfully |
400 |
Bad Request | Invalid request format or parameters |
403 |
Forbidden | Access denied |
404 |
Not Found | Resource not found (e.g., worker doesn't exist) |
405 |
Method Not Allowed | Wrong HTTP method used |
409 |
Conflict | Resource already exists |
422 |
Unprocessable Entity | Validation failed |
500 |
Internal Server Error | Server-side error occurred |
503 |
Service Unavailable | Database connection failed |
{
"success": false,
"error": "Error message describing what went wrong",
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0",
"details": {
"field_name": "Specific validation error"
}
}
{
"success": false,
"error": "Validation failed",
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0",
"details": {
"worker_id": "Worker ID is required",
"check_in": "Invalid datetime format. Use: Y-m-d H:i:s"
}
}
{
"success": false,
"error": "Worker not found",
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0",
"details": {
"worker_id": "WRK99999999"
}
}
{
"success": false,
"error": "Attendance already recorded for this date",
"timestamp": "2025-10-10 14:30:00",
"api_version": "1.0",
"details": {
"worker_id": "WRK20253975",
"date": "2025-10-10",
"suggestion": "Include check_out to update existing record"
}
}
sync_status field to track synchronization state between your biometric system and this API. Set it to "pending" when queuing data and "synced" after successful submission.
Solution:
config.phpSolution:
workers table/api/list-workers.php to get valid worker IDsFor development, you can enable detailed error messages in config.php:
// Development mode - shows detailed errors
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Production mode - logs errors, doesn't display
error_reporting(E_ALL);
ini_set('display_errors', 0);
ini_set('log_errors', 1);
For technical support, integration assistance, or to report issues: