- 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
21 KiB
API Endpoints Documentation
Dokumentasi lengkap semua endpoint yang tersedia di API Btekno.
Base URL: https://api.btekno.cloud
📋 Daftar Isi
- Public Endpoints
- Authentication
- Retribusi - Ingest
- Retribusi - Frontend CRUD
- Retribusi - Summary
- Retribusi - Dashboard
- Retribusi - Realtime
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 credentials403- User inactive422- 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 key404- Location/Gate/Tariff not found422- Validation error
Authentication: X-API-KEY header
Category Values:
person_walkmotorcar
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 found422- 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 found422- 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 found422- 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_KEYin.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 pagelimit- Items per pagetotal- Total itemspages- 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