Files
2025-07-11 14:07:20 +08:00

11 KiB

Nilai Clock Client - API Reference

Base Configuration

Production API Endpoint

https://myapp.ouji.com/nilai_clock_api/

Authentication

All protected endpoints require JWT Bearer token in the Authorization header:

Authorization: Bearer <jwt-token>

Common Headers

Content-Type: application/json
ngrok-skip-browser-warning: true

Authentication Endpoints

POST /api/auth/login

Authenticate user with username, password, and device UUID.

Request Body:

{
  "username": "string",
  "password": "string", 
  "deviceUuid": "string"
}

Success Response (200):

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
  "fullName": "Worker Full Name"
}

Error Responses:

  • 400: Missing required fields
  • 401: Invalid credentials
  • 403: Device not authorized

JWT Token Payload:

{
  "userId": 123,
  "role": "worker",
  "iat": 1642234567,
  "exp": 1642320967
}

POST /api/auth/refresh

Refresh expired JWT token.

Headers: Authorization: Bearer <current-token>

Success Response (200):

{
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Error Responses:

  • 401: Invalid or expired token
  • 500: Token refresh failed

Worker Endpoints

POST /api/clock

Record clock in/out event with location verification.

Headers: Authorization: Bearer <token>

Request Body:

{
  "userId": 123,
  "eventType": "clock_in", // or "clock_out"
  "qrCodeValue": "550e8400-e29b-41d4-a716-446655440000",
  "latitude": -6.2088,
  "longitude": 106.8456,
  "notes": "Optional notes"
}

Success Response (200):

{
  "message": "Clock in successful",
  "timestamp": "2024-01-15T08:00:00.000Z",
  "eventType": "clock_in",
  "location": {
    "latitude": -6.2088,
    "longitude": 106.8456
  }
}

Error Responses:

  • 400: Invalid event type or missing data
  • 401: Unauthorized
  • 403: Outside geofence area
  • 404: QR code not found or inactive
  • 409: Cannot clock in/out (already in same state)

Special Cases:

  • qrCodeValue: "FORCE_CLOCK_OUT" - Bypasses all validation checks

GET /api/worker/clock-history/:userId

Retrieve worker's clock in/out history.

Headers: Authorization: Bearer <token>

Parameters:

  • userId (path): Worker's user ID

Success Response (200):

[
  {
    "id": 1,
    "event_type": "clock_in",
    "timestamp": "2024-01-15T08:00:00.000Z",
    "qrCodeUsedName": "Main Entrance"
  },
  {
    "id": 2,
    "event_type": "clock_out", 
    "timestamp": "2024-01-15T17:00:00.000Z",
    "qrCodeUsedName": "Main Entrance"
  }
]

Error Responses:

  • 401: Unauthorized
  • 404: Worker not found
  • 500: Database error

GET /api/workers/:id

Get worker details by ID.

Headers: Authorization: Bearer <token>

Parameters:

  • id (path): Worker's user ID

Success Response (200):

{
  "full_name": "John Doe"
}

Error Responses:

  • 401: Unauthorized
  • 404: Worker not found
  • 500: Database error

Location & Tracking Endpoints

POST /api/location/update

Send location update to server (background tracking).

Headers: Authorization: Bearer <token>

Request Body:

{
  "userId": 123,
  "longitude": 106.8456,
  "latitude": -6.2088,
  "timestamp": "2024-01-15T08:00:00.000Z",
  "accuracy": 5.0,
  "source": "background" // or "manual", "clock_event"
}

Success Response (200):

{
  "message": "Location updated successfully",
  "timestamp": "2024-01-15T08:00:00.000Z"
}

Error Responses:

  • 400: Invalid location data
  • 401: Unauthorized
  • 500: Database error

GET /api/location/status/:userId

Get current location tracking status for user.

Headers: Authorization: Bearer <token>

Parameters:

  • userId (path): Worker's user ID

Success Response (200):

{
  "isTracking": true,
  "lastUpdate": "2024-01-15T08:00:00.000Z",
  "currentLocation": {
    "latitude": -6.2088,
    "longitude": 106.8456
  },
  "withinGeofence": true
}

Security Endpoints

POST /api/security/check - DEPRECATED

DEPRECATED: This endpoint has been commented out in favor of server-side security computation.

Client-side security calculation has been removed per user preference for server-side security validation. Anti-spoofing functionality (fake GPS detection, UUID validation) continues to work through existing server-side mechanisms.

GET /api/security/app-blacklist

Get list of blacklisted applications.

Headers: Authorization: Bearer <token>

Success Response (200):

[
  "com.lexa.fakegps",
  "com.incorporateapps.fakegps.fre",
  "com.blogspot.newapphorizons.fakegps",
  "com.theappninjas.gpsjoystick"
]

POST /api/security/alert - NOT IMPLEMENTED

NOT IMPLEMENTED: This endpoint was documented but never implemented in the server.

Security alerts are handled server-side through existing mechanisms:

  • Geofence violations are logged automatically during location updates
  • Device validation failures are logged during login attempts
  • High-risk device detection is handled by server-side security validation

GET /api/security/status/:userId

Get security status for user.

Headers: Authorization: Bearer <token>

Parameters:

  • userId (path): Worker's user ID

Success Response (200):

{
  "latestSecurityCheck": {
    "id": 100,
    "user_id": 123,
    "timestamp": "2024-01-15T08:00:00.000Z",
    "risk_level": "low",
    "risk_score": 10
  },
  "recentAlerts": [
    {
      "id": 456,
      "alert_type": "location_anomaly",
      "severity": "medium",
      "created_at": "2024-01-15T07:30:00.000Z"
    }
  ],
  "securityStatus": "low"
}

Device Management Endpoints

POST /api/device/register

Register device for user account.

Headers: Authorization: Bearer <token>

Request Body:

{
  "userId": 123,
  "deviceUuid": "android-550e8400-e29b-41d4-a716-446655440000"
}

Success Response (200):

{
  "message": "Device registered successfully",
  "deviceUuid": "android-550e8400-e29b-41d4-a716-446655440000",
  "registeredAt": "2024-01-15T08:00:00.000Z"
}

Error Responses:

  • 400: Invalid device UUID
  • 401: Unauthorized
  • 409: Device already registered to another user
  • 500: Database error

POST /api/device/validate

Validate device for user account.

Headers: Authorization: Bearer <token>

Request Body:

{
  "userId": 123,
  "deviceUuid": "android-550e8400-e29b-41d4-a716-446655440000"
}

Success Response (200):

{
  "valid": true,
  "message": "Device validated successfully",
  "deviceInfo": {
    "registeredAt": "2024-01-15T08:00:00.000Z",
    "lastSeen": "2024-01-15T08:00:00.000Z"
  }
}

Error Responses:

  • 400: Invalid device UUID
  • 401: Unauthorized
  • 403: Device not authorized for this user
  • 404: Device not found
  • 500: Database error

Note: Managers bypass device validation and always receive valid: true.

Manager Endpoints (Web Only)

GET /api/managers/workers

Get list of all workers with filtering and pagination.

Headers: Authorization: Bearer <token>

Query Parameters:

  • search (optional): Search term for worker names
  • page (optional): Page number (default: 1)
  • limit (optional): Items per page (default: 20)
  • tags (optional): Comma-separated tag IDs

Success Response (200):

{
  "workers": [
    {
      "id": 123,
      "username": "worker123",
      "full_name": "John Doe",
      "created_at": "2024-01-01T00:00:00.000Z",
      "tags": "Production, Day Shift"
    }
  ],
  "totalCount": 50,
  "currentPage": 1,
  "totalPages": 3
}

GET /api/managers/qr-codes

Get list of all QR codes.

Headers: Authorization: Bearer <token>

Success Response (200):

[
  {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "Main Entrance",
    "is_active": true,
    "created_at": "2024-01-01T00:00:00.000Z"
  }
]

POST /api/managers/qr-codes

Create new QR code.

Headers: Authorization: Bearer <token>

Request Body:

{
  "name": "Side Entrance"
}

Success Response (201):

{
  "id": "550e8400-e29b-41d4-a716-446655440001",
  "name": "Side Entrance",
  "is_active": true
}

Error Response Format

All endpoints return consistent error responses:

{
  "message": "Descriptive error message",
  "code": "ERROR_CODE",
  "details": {
    "field": "Additional error details"
  }
}

Common Error Codes

  • INVALID_CREDENTIALS: Login failed
  • TOKEN_EXPIRED: JWT token has expired
  • DEVICE_NOT_AUTHORIZED: Device not registered for user
  • OUTSIDE_GEOFENCE: Location outside allowed area
  • QR_CODE_INACTIVE: QR code is disabled
  • DUPLICATE_EVENT: Cannot perform same clock action twice
  • SECURITY_VIOLATION: Security check failed
  • VALIDATION_ERROR: Request data validation failed

HTTP Status Codes

  • 200: Success
  • 201: Created successfully
  • 400: Bad Request (validation errors)
  • 401: Unauthorized (invalid/missing token)
  • 403: Forbidden (insufficient permissions)
  • 404: Not Found
  • 409: Conflict (duplicate data)
  • 500: Internal Server Error

Rate Limiting

API endpoints are rate-limited to prevent abuse:

  • Authentication endpoints: 5 requests per minute per IP
  • Clock endpoints: 10 requests per minute per user
  • Location updates: 60 requests per minute per user
  • General endpoints: 100 requests per minute per user

Rate limit headers are included in responses:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1642234567

Webhook Events (Future)

The API supports webhook notifications for real-time events:

Clock Events

{
  "event": "worker.clock_in",
  "data": {
    "userId": 123,
    "timestamp": "2024-01-15T08:00:00.000Z",
    "location": {
      "latitude": -6.2088,
      "longitude": 106.8456
    }
  }
}

Security Alerts

{
  "event": "security.violation",
  "data": {
    "userId": 123,
    "alertType": "gps_spoofing_detected",
    "severity": "high",
    "timestamp": "2024-01-15T08:00:00.000Z"
  }
}

SDK Examples

JavaScript/TypeScript

class NilaiClockAPI {
  constructor(baseURL, token) {
    this.baseURL = baseURL
    this.token = token
  }
  
  async clockIn(userId, qrCodeValue, latitude, longitude) {
    const response = await fetch(`${this.baseURL}/api/clock`, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${this.token}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        userId,
        eventType: 'clock_in',
        qrCodeValue,
        latitude,
        longitude
      })
    })
    
    if (!response.ok) {
      throw new Error(`Clock in failed: ${response.status}`)
    }
    
    return response.json()
  }
}

cURL Examples

# Login
curl -X POST https://myapp.ouji.com/nilai_clock_api/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"username":"worker123","password":"password","deviceUuid":"device-uuid"}'

# Clock In
curl -X POST https://myapp.ouji.com/nilai_clock_api/api/clock \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"userId":123,"eventType":"clock_in","qrCodeValue":"qr-uuid","latitude":-6.2088,"longitude":106.8456}'

# Get History
curl -X GET https://myapp.ouji.com/nilai_clock_api/api/worker/clock-history/123 \
  -H "Authorization: Bearer <token>"