Salami Gateway

API Documentation
Back to Dashboard

Attendance API Overview

Salami Gateway provides a centralized attendance and biometric data collection API. On-premise sync agents push scan data from ZKTeco biometric devices to Salami, which stores the raw scans and distributes them to registered consumer systems (Hub, HimaHR, etc.) via HMAC-signed webhooks.

Base URL

https://your-domain.com/api/attendance

Authentication

Two authentication methods depending on the endpoint:

Method Used by Header
Device token Sync agents Authorization: Bearer {device_token}
App token Consumer apps Authorization: Bearer {app_token}

Unauthenticated endpoints (no token required):


Endpoints

Push Scans

Receive biometric scan data from a sync agent.

POST /api/attendance/scans/push
Authorization: Bearer {device_token}
Content-Type: application/json

Request body:

{
  "device_token": "abc123...",
  "scans": [
    {
      "uid": "1",
      "timestamp": "2026-04-15 08:23:45",
      "state": 0,
      "type": 0
    }
  ]
}
Field Type Description
device_token string Device API token (also sent in Authorization header)
scans[].uid string Device user ID (mapped to employee by the consumer)
scans[].timestamp string Scan time in Y-m-d H:i:s format
scans[].state int 0 = check-in, 1 = check-out (often unreliable, consumers use chronological order)
scans[].type int 0 = fingerprint, 1 = password, 2 = card

Response (200):

{
  "message": "Scans received.",
  "received": 150,
  "device_name": "Office 3",
  "batch_id": "a1b2c3d4-..."
}

Errors:

Code Reason
401 Invalid or inactive device token
422 Validation error (missing scans, etc.)

Device Status

Check if a device token is valid and the device is active.

GET /api/attendance/scans/status?device_token={token}
Authorization: Bearer {device_token}

Response (200):

{
  "device_id": 5,
  "name": "Office 3",
  "is_active": true,
  "last_synced_at": "2026-04-15T08:30:00+03:00",
  "device_type": "zkteco"
}

List Scans

Fetch stored scans for a date range. Used by consumer apps for polling (alternative to webhooks).

GET /api/attendance/scans?from=2026-04-01&to=2026-04-15
Authorization: Bearer {app_token}
Parameter Required Description
from Yes Start date (Y-m-d)
to Yes End date (Y-m-d)
device_token No Filter by specific device
page No Pagination (default 1)

Response (200): Paginated scan records.


Agent Downloads

Public endpoint returning sync agent binaries and setup instructions for each OS.

GET /api/attendance/agent/downloads

Response (200):

{
  "agent_version": "3.2",
  "downloads": {
    "windows": "/downloads/salami-sync-agent.exe",
    "mac_intel": "/downloads/salami-sync-agent-mac-intel",
    "mac_arm": "/downloads/salami-sync-agent-mac-arm64",
    "linux": "/downloads/salami-sync-agent-linux-amd64"
  },
  "setup": {
    "windows": {
      "steps": ["1. Download .exe", "2. Create config.json", "3. Run"],
      "example_config": { "..." }
    }
  }
}

BioTime Sync (Manual Trigger)

Trigger a manual sync of attendance data from ZKTeco BioTime cloud.

POST /api/attendance/biotime/sync
Authorization: Bearer {app_token}

Response (200):

{
  "message": "BioTime sync completed.",
  "synced": 45,
  "batch_id": "a1b2c3d4-...",
  "device_name": "BioTime Cloud"
}

Webhook Delivery

When scans are received (from agents or BioTime), Salami dispatches webhooks to all registered consumers.

Payload

{
  "event": "scans.received",
  "batch_id": "a1b2c3d4-...",
  "device_token": "abc123...",
  "device_name": "Office 3",
  "scans": [
    {
      "uid": "1",
      "timestamp": "2026-04-15 08:23:45",
      "state": 0,
      "type": 0
    }
  ]
}

Headers

Content-Type: application/json
X-Salami-Signature: sha256={hmac_hash}

Signature Verification

The X-Salami-Signature header contains an HMAC-SHA256 hash of the request body signed with the shared secret configured when registering the webhook.

PHP example:

$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_SALAMI_SIGNATURE'];
$expected = 'sha256=' . hash_hmac('sha256', $payload, $webhookSecret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

Data Sources

Source Method Description
ZKTeco devices Sync agent pushes to /scans/push On-premise UDP connection to biometric devices
BioTime cloud Scheduled command or /biotime/sync REST API pull from ZKTeco BioTime SaaS
Manual entry Future Direct scan entry via API

Need help? Contact us at support@dgl.co.ke
© 2026 Deadan Group Limited. All rights reserved.
⚡ API Explorer
LIVE
// Response will appear here...