Files
api-btekno/API_ENDPOINTS.md
mwpn 820a0600ed docs: update API_ENDPOINTS.md dengan endpoint baru dan field camera
- Tambah dokumentasi GET /locations/{code} (detail location)
- Tambah dokumentasi GET /gates/{location_code}/{gate_code} (detail gate)
- Tambah dokumentasi GET /tariffs (list tariffs)
- Tambah dokumentasi GET /tariffs/{location_code}/{gate_code}/{category} (detail tariff)
- Tambah dokumentasi GET /audit-logs (audit trail)
- Tambah dokumentasi GET /entry-events (raw entry events)
- Tambah dokumentasi GET /realtime/events (realtime events list)
- Update response examples untuk include field camera di gates
- Tambah note tentang format camera (HLS, RTSP, HTTP, Camera ID)
- Update daftar isi dengan struktur endpoint baru
2025-12-18 06:42:27 +07:00

21 KiB

API Endpoints Documentation

Dokumentasi lengkap semua endpoint yang tersedia di API Btekno.

Base URL: https://api.btekno.cloud


📋 Daftar Isi


Public Endpoints

Health Check

GET /health

Health check endpoint untuk monitoring.

Response:

{
  "status": "ok",
  "time": 1703123456
}

Documentation

GET /

Redirect ke /docs (Swagger UI).

GET /docs

Swagger UI documentation (public access).

GET /docs/openapi.json

OpenAPI 3.0 specification JSON.


Authentication

Login

POST /auth/v1/login

Login untuk mendapatkan JWT token.

Request Body:

{
  "username": "admin",
  "password": "password123"
}

Response (200):

{
  "success": true,
  "data": {
    "token": "eyJ0eXAiOiJKV1QiLCJhbGc...",
    "expires_in": 3600,
    "user": {
      "id": 1,
      "username": "admin",
      "role": "admin"
    }
  },
  "timestamp": 1703123456
}

Error Responses:

  • 401 - Invalid credentials
  • 403 - User inactive
  • 422 - Validation error

Authentication: None (public endpoint)


Retribusi - Ingest

Ingest Event

POST /retribusi/v1/ingest

Endpoint untuk mesin/IoT mengirim event data.

Headers:

X-API-KEY: your-api-key-here
Content-Type: application/json

Request Body:

{
  "timestamp": 1703123456,
  "location_code": "kerkof_01",
  "gate_code": "gate01",
  "category": "motor"
}

Response (200):

{
  "success": true,
  "data": {
    "stored": true
  },
  "timestamp": 1703123456
}

Error Responses:

  • 401 - Invalid API key
  • 404 - Location/Gate/Tariff not found
  • 422 - Validation error

Authentication: X-API-KEY header

Category Values:

  • person_walk
  • motor
  • car

Retribusi - Frontend CRUD

Semua endpoint di bawah ini memerlukan JWT Authentication.

Headers:

Authorization: Bearer <jwt-token>
Content-Type: application/json

Locations

List Locations

GET /retribusi/v1/frontend/locations

Get list of locations dengan pagination.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)

Response (200):

{
  "success": true,
  "data": [
    {
      "code": "kerkof_01",
      "name": "Kerkof 01",
      "type": "kerkof",
      "is_active": 1
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 10,
    "pages": 1
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Get Location Detail

GET /retribusi/v1/frontend/locations/{code}

Get detail location berdasarkan code.

Response (200):

{
  "success": true,
  "data": {
    "code": "kerkof_01",
    "name": "Kerkof 01",
    "type": "kerkof",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Error Responses:

  • 404 - Location not found
  • 422 - Invalid location code

Access: Viewer, Operator, Admin


Create Location

POST /retribusi/v1/frontend/locations

Create new location.

Request Body:

{
  "code": "kerkof_02",
  "name": "Kerkof 02",
  "type": "kerkof",
  "is_active": 1
}

Response (201):

{
  "success": true,
  "data": {
    "code": "kerkof_02",
    "name": "Kerkof 02",
    "type": "kerkof",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Update Location

PUT /retribusi/v1/frontend/locations/{code}

Update location (code tidak bisa diubah).

Request Body:

{
  "name": "Kerkof 02 Updated",
  "type": "kerkof",
  "is_active": 1
}

Response (200):

{
  "success": true,
  "data": {
    "code": "kerkof_02",
    "name": "Kerkof 02 Updated",
    "type": "kerkof",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Delete Location

DELETE /retribusi/v1/frontend/locations/{code}

Soft delete location (set is_active = 0).

Response (200):

{
  "success": true,
  "data": {
    "deleted": true
  },
  "timestamp": 1703123456
}

Access: Admin only


Gates

List Gates

GET /retribusi/v1/frontend/gates

Get list of gates dengan pagination.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)

Response (200):

{
  "success": true,
  "data": [
    {
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "name": "Gate 01",
      "direction": "in",
      "camera": "https://example.com/stream.m3u8",
      "is_active": 1
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 5,
    "pages": 1
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Get Gate Detail

GET /retribusi/v1/frontend/gates/{location_code}/{gate_code}

Get detail gate berdasarkan location_code dan gate_code.

Response (200):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate01",
    "name": "Gate 01",
    "direction": "in",
    "camera": "https://example.com/stream.m3u8",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Error Responses:

  • 404 - Gate not found
  • 422 - Invalid location_code or gate_code

Access: Viewer, Operator, Admin


Create Gate

POST /retribusi/v1/frontend/gates

Create new gate.

Request Body:

{
  "location_code": "kerkof_01",
  "gate_code": "gate02",
  "name": "Gate 02",
  "direction": "out",
  "camera": "rtsp://192.168.1.100:554/stream1",
  "is_active": 1
}

Note: Field camera optional, bisa diisi dengan:

  • HLS URL: https://example.com/stream.m3u8
  • RTSP URL: rtsp://192.168.1.100:554/stream1
  • HTTP URL: http://192.168.1.100:8080/camera1
  • Camera ID: camera_001

Response (201):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate02",
    "name": "Gate 02",
    "direction": "out",
    "camera": "rtsp://192.168.1.100:554/stream1",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Update Gate

PUT /retribusi/v1/frontend/gates/{location_code}/{gate_code}

Update gate (location_code dan gate_code tidak bisa diubah).

Request Body:

{
  "name": "Gate 02 Updated",
  "direction": "out",
  "camera": "http://192.168.1.100:8080/hls/stream.m3u8",
  "is_active": 1
}

Note: Field camera optional, bisa diisi dengan:

  • HLS URL: https://example.com/stream.m3u8
  • RTSP URL: rtsp://192.168.1.100:554/stream1
  • HTTP URL: http://192.168.1.100:8080/camera1
  • Camera ID: camera_001

Response (200):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate02",
    "name": "Gate 02 Updated",
    "direction": "out",
    "camera": "http://192.168.1.100:8080/hls/stream.m3u8",
    "is_active": 1
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Delete Gate

DELETE /retribusi/v1/frontend/gates/{location_code}/{gate_code}

Soft delete gate (set is_active = 0).

Response (200):

{
  "success": true,
  "data": {
    "deleted": true
  },
  "timestamp": 1703123456
}

Access: Admin only


Tariffs

List Tariffs

GET /retribusi/v1/frontend/tariffs

Get list of tariffs dengan pagination.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)
  • gate_code (optional, filter)

Response (200):

{
  "success": true,
  "data": [
    {
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "category": "motor",
      "price": 5000,
      "location_name": "Kerkof 01",
      "gate_name": "Gate 01"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 10,
    "pages": 1
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Get Tariff Detail

GET /retribusi/v1/frontend/tariffs/{location_code}/{gate_code}/{category}

Get detail tariff berdasarkan location_code, gate_code, dan category.

Response (200):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate01",
    "category": "motor",
    "price": 5000
  },
  "timestamp": 1703123456
}

Error Responses:

  • 404 - Tariff not found
  • 422 - Invalid location_code, gate_code, or category

Access: Viewer, Operator, Admin


Create Tariff

POST /retribusi/v1/frontend/tariffs

Create new tariff.

Request Body:

{
  "location_code": "kerkof_01",
  "gate_code": "gate01",
  "category": "motor",
  "price": 5000
}

Response (201):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate01",
    "category": "motor",
    "price": 5000
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Update Tariff

PUT /retribusi/v1/frontend/tariffs/{location_code}/{gate_code}/{category}

Update tariff price (location_code, gate_code, category tidak bisa diubah).

Request Body:

{
  "price": 6000
}

Response (200):

{
  "success": true,
  "data": {
    "location_code": "kerkof_01",
    "gate_code": "gate01",
    "category": "motor",
    "price": 6000
  },
  "timestamp": 1703123456
}

Access: Operator, Admin


Delete Tariff

DELETE /retribusi/v1/frontend/tariffs/{location_code}/{gate_code}/{category}

Hard delete tariff (permanent delete).

Response (200):

{
  "success": true,
  "data": {
    "deleted": true
  },
  "timestamp": 1703123456
}

Access: Admin only


Streams

List Streams

GET /retribusi/v1/frontend/streams

Get list of streams (alias untuk gates).

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)

Response (200):

{
  "success": true,
  "data": [
    {
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "name": "Gate 01",
      "direction": "in",
      "is_active": 1
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 5,
    "pages": 1
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Audit Logs

List Audit Logs

GET /retribusi/v1/frontend/audit-logs

Get audit trail history dengan pagination dan filter.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • entity (optional, filter: locations|gates|tariffs)
  • action (optional, filter: create|update|delete)
  • entity_key (optional, filter by specific entity key)
  • start_date (optional, format: YYYY-MM-DD)
  • end_date (optional, format: YYYY-MM-DD)

Response (200):

{
  "success": true,
  "data": [
    {
      "id": 123,
      "actor_user_id": 1,
      "actor_username": "admin",
      "actor_role": "admin",
      "action": "update",
      "entity": "locations",
      "entity_key": "kerkof_01",
      "before_json": {
        "code": "kerkof_01",
        "name": "Kerkof 01",
        "type": "kerkof",
        "is_active": 1
      },
      "after_json": {
        "code": "kerkof_01",
        "name": "Kerkof 01 Updated",
        "type": "kerkof",
        "is_active": 1
      },
      "ip_address": "192.168.1.100",
      "user_agent": "Mozilla/5.0...",
      "created_at": "2025-01-17 10:30:00"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 150,
    "pages": 8
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Entry Events

List Entry Events

GET /retribusi/v1/frontend/entry-events

Get list of raw entry events (data mentah dari mesin) dengan pagination dan filter.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)
  • gate_code (optional, filter)
  • category (optional, filter)
  • start_date (optional, format: YYYY-MM-DD)
  • end_date (optional, format: YYYY-MM-DD)

Response (200):

{
  "success": true,
  "data": [
    {
      "id": 12345,
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "category": "motor",
      "event_time": "2025-01-17 10:30:00",
      "source_ip": "192.168.1.100",
      "created_at": "2025-01-17 10:30:01"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 5000,
    "pages": 250
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin

Note: Endpoint ini berguna untuk debugging dan admin untuk melihat raw event data.


Retribusi - Summary

Semua endpoint di bawah ini memerlukan JWT Authentication.

Daily Summary

Trigger Daily Aggregation

POST /retribusi/v1/admin/summary/daily

Trigger manual aggregation untuk daily summary.

Request Body:

{
  "date": "2025-12-16"
}

Response (200):

{
  "success": true,
  "data": {
    "rows_processed": 150,
    "date": "2025-12-16"
  },
  "timestamp": 1703123456
}

Access: Admin only


Get Daily Summary

GET /retribusi/v1/summary/daily

Get daily summary data.

Query Parameters:

  • date (required, format: YYYY-MM-DD)
  • location_code (optional, filter)
  • gate_code (optional, filter)

Response (200):

{
  "success": true,
  "data": [
    {
      "summary_date": "2025-12-16",
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "category": "motor",
      "total_count": 100,
      "total_amount": 500000
    }
  ],
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Hourly Summary

Get Hourly Summary

GET /retribusi/v1/summary/hourly

Get hourly summary data untuk chart (24 jam).

Query Parameters:

  • date (required, format: YYYY-MM-DD)
  • location_code (optional, filter)
  • gate_code (optional, filter)

Response (200):

{
  "success": true,
  "data": {
    "labels": ["00", "01", "02", ..., "23"],
    "series": {
      "total_count": [10, 15, 20, ..., 5],
      "total_amount": [50000, 75000, 100000, ..., 25000]
    }
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Retribusi - Dashboard

Semua endpoint di bawah ini memerlukan JWT Authentication.

Daily Chart

GET /retribusi/v1/dashboard/daily

Get daily chart data (line chart).

Query Parameters:

  • start_date (required, format: YYYY-MM-DD)
  • end_date (required, format: YYYY-MM-DD)
  • location_code (optional, filter)
  • gate_code (optional, filter)

Response (200):

{
  "success": true,
  "data": {
    "labels": ["2025-12-01", "2025-12-02", "2025-12-03"],
    "series": {
      "total_count": [100, 150, 200],
      "total_amount": [500000, 750000, 1000000]
    }
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


By Category Chart

GET /retribusi/v1/dashboard/by-category

Get chart data grouped by category (bar/donut chart).

Query Parameters:

  • date (required, format: YYYY-MM-DD)
  • location_code (optional, filter)
  • gate_code (optional, filter)

Response (200):

{
  "success": true,
  "data": {
    "labels": ["person_walk", "motor", "car"],
    "series": {
      "total_count": [50, 100, 30],
      "total_amount": [100000, 500000, 300000]
    }
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Summary Statistics

GET /retribusi/v1/dashboard/summary

Get summary statistics (stat cards).

Query Parameters:

  • date (required, format: YYYY-MM-DD)
  • location_code (optional, filter)

Response (200):

{
  "success": true,
  "data": {
    "total_count_today": 180,
    "total_amount_today": 900000,
    "by_gate": [
      {
        "gate_code": "gate01",
        "total_count": 100,
        "total_amount": 500000
      }
    ],
    "by_category": [
      {
        "category": "motor",
        "total_count": 100,
        "total_amount": 500000
      }
    ]
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Retribusi - Realtime

Semua endpoint di bawah ini memerlukan JWT Authentication.

SSE Stream

GET /retribusi/v1/realtime/stream

Server-Sent Events (SSE) stream untuk real-time updates.

Headers:

Authorization: Bearer <jwt-token>
Accept: text/event-stream

Query Parameters:

  • last_id (optional, untuk resume dari event tertentu)
  • location_code (optional, filter)

Response (200):

Content-Type: text/event-stream
Cache-Control: no-cache
Connection: keep-alive

id: 12345
event: ingest
data: {"location_code":"kerkof_01","gate_code":"gate01","category":"motor","event_time":1703123456}

id: 12346
event: ingest
data: {"location_code":"kerkof_01","gate_code":"gate01","category":"car","event_time":1703123457}

...

Access: Viewer, Operator, Admin

Note: Connection akan tetap terbuka dan mengirim event setiap ada ingest baru. Ping dikirim setiap 10 detik jika tidak ada data.


Snapshot

GET /retribusi/v1/realtime/snapshot

Get snapshot data untuk real-time dashboard cards.

Query Parameters:

  • date (optional, default: today, format: YYYY-MM-DD)
  • location_code (optional, filter)

Response (200):

{
  "success": true,
  "data": {
    "total_count_today": 180,
    "total_amount_today": 900000,
    "by_gate": [
      {
        "gate_code": "gate01",
        "total_count": 100,
        "total_amount": 500000
      }
    ],
    "by_category": [
      {
        "category": "motor",
        "total_count": 100,
        "total_amount": 500000
      }
    ]
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin


Realtime Events

List Realtime Events

GET /retribusi/v1/realtime/events

Get list of realtime events (history events untuk SSE) dengan pagination dan filter.

Query Parameters:

  • page (optional, default: 1)
  • limit (optional, default: 20, max: 100)
  • location_code (optional, filter)
  • gate_code (optional, filter)
  • category (optional, filter)
  • start_date (optional, format: YYYY-MM-DD)
  • end_date (optional, format: YYYY-MM-DD)

Response (200):

{
  "success": true,
  "data": [
    {
      "id": 12345,
      "location_code": "kerkof_01",
      "gate_code": "gate01",
      "category": "motor",
      "event_time": 1703123456,
      "total_count_delta": 1,
      "created_at": "2025-01-17 10:30:01"
    }
  ],
  "meta": {
    "page": 1,
    "limit": 20,
    "total": 1000,
    "pages": 50
  },
  "timestamp": 1703123456
}

Access: Viewer, Operator, Admin

Note: event_time adalah Unix timestamp (integer). Endpoint ini untuk melihat history events yang sudah masuk ke realtime_events table.


Error Responses

Semua endpoint mengembalikan error dalam format konsisten:

401 Unauthorized

{
  "error": "unauthorized",
  "message": "Invalid or expired token"
}

403 Forbidden

{
  "error": "forbidden",
  "message": "Insufficient permissions"
}

404 Not Found

{
  "error": "not_found",
  "message": "Resource not found"
}

409 Conflict

{
  "error": "conflict",
  "message": "Resource already exists"
}

422 Validation Error

{
  "error": "validation_error",
  "fields": {
    "location_code": "Field is required",
    "price": "Must be >= 0"
  }
}

500 Server Error

{
  "error": "server_error",
  "message": "Internal server error"
}

Authentication & Authorization

JWT Token

  • Algorithm: HS256
  • TTL: Configurable via JWT_TTL_SECONDS (default: 3600 seconds)
  • Header: Authorization: Bearer <token>

Roles

  • viewer - Read-only access
  • operator - Read + Write (POST, PUT)
  • admin - Full access (Read + Write + Delete)

API Key (Ingest)

  • Header: X-API-KEY: <api-key>
  • Config: RETRIBUSI_API_KEY in .env

Rate Limiting

Saat ini tidak ada rate limiting. Untuk production, pertimbangkan untuk menambahkan rate limiting middleware.


Pagination

Semua list endpoints mendukung pagination:

  • page - Page number (default: 1)
  • limit - Items per page (default: 20, max: 100)

Response selalu include meta object dengan:

  • page - Current page
  • limit - Items per page
  • total - Total items
  • pages - Total pages

Timestamps

Semua response include timestamp field (Unix timestamp).

Untuk date parameters, gunakan format: YYYY-MM-DD

Untuk datetime, gunakan format: YYYY-MM-DD HH:MM:SS atau Unix timestamp (integer).


Support

Untuk pertanyaan atau issue, silakan hubungi tim development.

Last Updated: 2025-12-17