14 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
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",
"is_active": 1
}
],
"meta": {
"page": 1,
"limit": 20,
"total": 5,
"pages": 1
},
"timestamp": 1703123456
}
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",
"is_active": 1
}
Response (201):
{
"success": true,
"data": {
"location_code": "kerkof_01",
"gate_code": "gate02",
"name": "Gate 02",
"direction": "out",
"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",
"is_active": 1
}
Response (200):
{
"success": true,
"data": {
"location_code": "kerkof_01",
"gate_code": "gate02",
"name": "Gate 02 Updated",
"direction": "out",
"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
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
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
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