Dokumentasi publik — untuk pengembang aplikasi mobile. Semua endpoint di bawah base URL di bawah.
https://tikhub.id/api/v1
Authorization: Bearer <token>
JSON — { success, message, data, code }
| X-App-Package | id.tikhub | Package name aplikasi |
| X-App-Platform | android | Platform: android / ios |
| X-App-Version-Code | 3 | versionCode aplikasi (angka) |
| X-App-Version-Name | v.3 | versionName aplikasi |
Alur kerja aplikasi mobile. 1 login = 1 session. Dalam 1 session customer hanya boleh memilih SATU device. Semua fungsi (profile, voucher, transaksi) otomatis memakai device yang dipilih — tidak perlu kirim device_id ulang.
POST /api/v1/auth/login
public
Kirim identifier (email ATAU HP) + password → token Bearer (berlaku 30 hari). Semua role bisa login app (owner/administrator/operator). Simpan token utk semua request berikutnya (header Authorization).
GET /api/v1/devices
auth
Ambil daftar device milik customer (dari customers_assign, status active). Session baru = belum ada pilihan → semua is_selected=false. Tiap device menyertakan logo/logo_url (bila ada) — utk app simpan lokal & cetak voucher.
POST /api/v1/devices/select
auth
Set device sbg selected dgn body { device_id }. Hanya bisa SEKALI per session. Pilih device yg SAMA lagi = idempotent (OK). Pilih device LAIN ditolak (DEVICE_LOCKED) — harus logout dulu. Respons membawa voucher_template (termasuk logo) device tsb → app simpan logo di local storage (keyed by device_id).
GET /api/v1/devices/detail
auth
Informasi device (uptime, versi, board, CPU, RAM) + customer detail + voucher_template (branding utk cetak). device_id boleh kosong → memakai selected device.
GET /api/v1/profiles
auth
Daftar paket (profile) utk dipilih user. device_id boleh kosong → memakai selected device.
POST /api/v1/vouchers/generate
auth
Buat 1..N voucher ke selected device + catat transaksi (status paid). device_id boleh kosong → memakai selected device. Harga transaksi = customers_store.price (bila kirim store_id); alur cetak: store (katalog+harga) → voucher_template (branding) → cetak voucher.
GET /api/v1/transactions?month=YYYY-MM
auth
Riwayat + LAPORAN penjualan voucher. Pilih rentang dgn SALAH SATU: CUSTOM `from`/`start_date` → `to`/`end_date` (inklusif) · BULAN `month=YYYY-MM` · TAHUN `year=YYYY` · PRESET `period=today|yesterday|7d|30d|this_month|last_month|this_year|last_year|all`. Filter tambahan: device_id, status, profile, q. Paging: limit (default 200/maks 1000) + page|offset, urut order=asc|desc. Respons memuat meta.total & summary (jumlah transaksi + omzet). Utk mengisi PICKER periode di app panggil GET /api/v1/transactions/periods (daftar bulan/tahun yg ada data); utk grafik harian pakai GET /api/v1/transactions/summary (by_date/by_profile/by_device/by_status). Owner & administrator melihat semua device organisasinya; operator hanya device miliknya.
GET /api/v1/quick_stats
auth
Ringkasan dashboard: jumlah sesi hotspot aktif di selected device + jumlah transaksi hari ini. Bisa dipanggil kapan saja setelah login.
POST /api/v1/auth/logout
auth
Menonaktifkan token & menghapus pilihan device. WAJIB utk bisa memilih device LAIN: logout → login → pilih device baru.
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| POST |
/api/v1/auth/login
public
|
Login customer (email/HP + password) → token Bearer. Bila customer sudah upload logo voucher, ikut dikirim `logo` (nama file) & `logo_url` (path publik) — dipakai app utk cetak voucher. |
identifier · stringpassword · string |
| POST |
/api/v1/auth/logout
auth
|
Logout: menonaktifkan token & menghapus pilihan device (session berakhir). WAJIB utk bisa memilih device lain. |
—
|
| GET |
/api/v1/auth/me
auth
|
Profil user yg login (id = user_id, org_id = id org/owner; role & organization_name disertakan). Bila sudah upload logo voucher, ikut dikirim `logo` & `logo_url` (null bila belum ada) — utk cetak voucher. |
—
|
| POST |
/api/v1/auth/forgot
public
|
Lupa password (dari halaman login app mobile). Kirim email/HP → OTP 6 digit dikirim ke email & WhatsApp (purpose=`forgot_password` di tabel `customer_otp`, berlaku 5 menit). Respons SELALU sama (tidak mengungkap akun terdaftar/tidak). |
identifier · stringemail? · string |
| POST |
/api/v1/auth/forgot/verify
public
|
Verifikasi OTP reset password → balikin `reset_token` (sekali pakai, berlaku sesuai OTP 5 menit). |
identifier · stringotp · string |
| POST |
/api/v1/auth/reset_password
public
|
Set password baru dgn `reset_token` (hasil verify). Otomatis menonaktifkan SEMUA token API customer (keamanan) → login ulang dgn password baru. |
identifier · stringreset_token · stringnew_password · string |
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| INFO |
—
public
|
Owner: login web & app, akses penuh. Administrator: login web & app, semua kelola operasional (di bawah owner). Operator: HANYA app mobile, khusus cetak voucher + baca riwayat — endpoint dibatasi 403 ROLE_FORBIDDEN di luar whitelist: devices (list/select/detail/selected), store (GET), voucher_template (GET), vouchers/generate, vouchers (GET), transactions (GET daftar), transactions/summary (GET laporan), transactions/:id (GET detail — hanya device miliknya), quick_stats (GET), profile/update, auth/me, auth/logout. |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/devices
auth
|
Daftar device milik customer (dari customers_assign, status active) + flag is_selected + logo/logo_url (bila device punya voucher setup berlogo) — utk app simpan lokal & cetak voucher. |
—
|
| POST |
/api/v1/devices/select
auth
|
Set device yg dipilih (SEKALI per session, disimpan di token). Respons juga membawa **voucher_template** — logo voucher ada di `data.voucher_template.logo` (URL `/uploads/voucher_logos/...`; null bila belum upload). App langsung dapat logo utk device ini sekali pilih, simpan di local storage (keyed by device_id) utk cetak voucher & akses ringan. Pilih device SAMA lagi = idempotent; pilih device LAIN ditolak DEVICE_LOCKED — harus logout dulu. |
device_id · string |
| GET |
/api/v1/devices/detail?device_id=RTR-XXX
auth
query: device_id?
|
Informasi device (resource & identity router) + **customer detail** + **voucher_template** (branding utk cetak thermal 58mm). Logo voucher ada di `data.voucher_template.logo` (URL `/uploads/voucher_logos/...`; null bila belum upload). Satu panggilan setelah select device → app siap cetak. device_id OPSIONAL — jika kosong memakai selected device. |
—
|
| GET |
/api/v1/devices/selected
auth
|
Device yg sedang terpilih (per session; null jika belum pilih). |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/profiles?device_id=RTR-XXX
auth
query: device_id?
|
Daftar bandwidth profile milik device customer. device_id OPSIONAL — jika kosong memakai selected device (lihat Device Selector). |
—
|
| POST |
/api/v1/profiles
auth
|
Buat bandwidth profile baru. |
device_id · stringname · stringrate? · stringburst? · stringsession_timeout? · stringtimebase? · stringquota_mb? · numberprice? · numbermasa_aktif? · string |
| PUT |
/api/v1/profiles/:id
auth
path: id
|
Update profile (id = .id profile di router, cth "*9"). ⚠️ Method PUT diblokir WAF nginx di server publik → pakai POST /api/v1/profiles/update. |
device_id · stringname · stringrate, burst, session_timeout, timebase, quota_mb, price, masa_aktif? · mixed |
| POST |
/api/v1/profiles/update
auth
|
Update profile — DISARANKAN (alias PUT /profiles/:id). WAF nginx memblokir method PUT/DELETE dgn 403, jadi app mobile sebaiknya memakai POST. |
id · stringdevice_id · stringname · stringrate, burst, session_timeout, timebase, quota_mb, price, masa_aktif? · mixed |
| POST |
/api/v1/profiles/delete
auth
|
Hapus profile — DISARANKAN (id RouterOS berisi `*` yg bermasalah di URL bila di-encode). |
device_id · stringid · stringname? · string |
| DELETE |
/api/v1/profiles/:id?device_id=RTR-XXX&name=NAMA
auth
path: id
query: device_id
query: name?
|
Hapus profile (alternatif REST; id dikirim mentah di path). |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| POST |
/api/v1/vouchers/generate
auth
|
Generate 1..N voucher: buat user hotspot di router + catat transaksi (status paid). device_id OPSIONAL — jika kosong memakai selected device. Harga yg disimpan ke transaksi = customers_store.price (bila store_id diisi); harga bandwidth_plan hanya acuan. **Username & password dibuat otomatis mengikuti user_hotspot_setup GLOBAL** (username_length, password_length, prefix, enabled_prefix, username_as_password). Bila opsi **username_as_password = yes** → password = username (pelanggan cukup 1 kode di halaman login hotspot). Format: tanpa prefix → digit awal + huruf kecil/angka; dengan prefix → prefix huruf kecil + kode bebas. Prefix di body meng-override prefix global (otomatis huruf kecil). |
device_id? · stringstore_id? · numberprofile? · stringquantity? · numberprefix? · string |
| GET |
/api/v1/vouchers?device_id=RTR-XXX&limit=50
auth
query: device_id?
query: limit?
|
Riwayat voucher / user yang pernah dibuat (dari transaksi customer). |
—
|
| GET |
/api/v1/voucher_check?username=<user>
auth
query: username
query: device_id?
|
Cek PEMAKAIAN hotspot per username. device_id opsional → fallback selected device (owner/admin) / device pribadi (operator). Data: `user` (profile, disabled, limit), `limit_status` (ok/habis_waktu/habis_kuota + detail time/volume via computeEffectiveUserLimit — gabung limit user + profil router), `cumulative` (pemakaian total user: uptime, bytes_in/out, packets), `usage` (sesi AKTIF: online, address, mac, hostname, uptime, session_time_left, idle_time, bytes, packets), `masa_aktif` (activationAt, expiryAt, habis, pct). Router offline → fallback mirror hotspot_users (DB), `router_online:false`. User tidak ditemukan → `404 USER_NOT_FOUND`. |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/transactions?month=2026-09&limit=50&page=1
auth
query: from?
query: to?
query: month?
query: year?
query: period?
query: device_id?
query: status?
query: profile?
query: q?
query: limit?
query: page?
query: order?
|
Daftar transaksi penjualan + RINGKASAN rentang/periode. `data` = baris transaksi (terbaru dulu), `meta` = info paging + mode rentang yg dipakai (`range_mode`, `from`, `to`, `month`, `year`, `period`) + jumlah baris yg cocok, `summary` = total transaksi & OMZET (app tak perlu hitung sendiri). Tanpa parameter rentang → semua tanggal (tetap dibatasi `limit`). |
—
|
| GET |
/api/v1/transactions/periods
auth
query: device_id?
|
OPSI YANG BISA DIPILIH app (picker Custom / Bulan / Tahun). `presets` = preset siap pakai + rentang tanggal hasil hitung server; `months` = daftar BULAN yang punya transaksi (`value`=YYYY-MM, `label`=mis. "September 2026", `transactions`, `amount`) urut terbaru; `years` = daftar TAHUN yang punya transaksi; `range` = `first_at`/`last_at` (batas pilihan custom) + `total_transactions`/`total_amount` semua periode. Kosongkan pilihan → pakai `period=all`. |
—
|
| GET |
/api/v1/transactions/summary?month=2026-09
auth
query: from?
query: to?
query: month?
query: year?
query: period?
query: device_id?
query: status?
query: profile?
query: q?
|
RINGKASAN penjualan pada rentang/periode — utk halaman Laporan/grafik app. Isi `data`: total transaksi/omzet/qty + rata-rata (`avg_amount`), rincian `by_date` (rupiah & jumlah per hari, urut tanggal NAIK → siap langsung dipakai grafik), `by_profile`, `by_device`, dan `by_status`. Filter rentang & aturan akses persis sama dgn daftar transaksi (custom from/to · month · year · period). |
—
|
| GET |
/api/v1/transactions/:id
auth
path: id
|
Detail satu transaksi (milik organisasi yg login). Operator hanya bisa membuka transaksi device miliknya — selain itu 404 NOT_FOUND. |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/quick_stats
auth
|
Statistik singkat dashboard: jumlah sesi hotspot AKTIF di selected device (live dari RouterOS) + jumlah transaksi customer HARI INI. Menyediakan juga `active_user_hotspot` (counter alias) & `active_users_hotspot` (LIST detail sesi aktif: user, address, mac_address, hostname, profile, server, uptime, session_time_left, idle_time, bytes_in/out, packets_in/out — di-enrich hostname dari DHCP lease & profile dari /ip/hotspot/user/print). Non-fatal (router offline/tidak ada selected device → active_hotspot 0, active_users_hotspot []). |
—
|
| GET |
/api/v1/users_active_list
auth
query: device_id?
|
LIST & counter sesi user hotspot aktif per device. `device_id` opsional → fallback selected device (owner/admin) / device pribadi (operator). **Selalu ter-scope sesuai device_id** — resolve via role-aware helper: owner/admin device harus milik org, operator HANYA device pribadinya; device bukan miliknya → `404 NOT_FOUND`. List di-enrich: user, address, mac_address, hostname (DHCP lease), profile (/ip/hotspot/user), server, uptime, session_time_left, idle_time, bytes_in/out, packets_in/out. Non-fatal: router offline → users=[], total=0 (tetap 200, device_id dikembalikan). |
—
|
| GET |
/api/v1/version
public
query: app_version_code?
query: platform?
|
VERSI APP MOBILE utk cek update. PUBLIC — tanpa token (bisa dicek sebelum login). Sumber: tabel `customers_api_versioning` (CRUD di menu Customers → Customers API Versioning); fallback `mobile_apps` (APK terakhir), lalu config/app-changelog.json. **Aturan**: `versionCode_app >= versionCode_server` → tidak perlu update; `<` → perlu update (unduh `download_url`); `< min_supported_version_code` atau versi ditandai wajib → **update WAJIB**. Kirim versi app agar server menghitung sendiri: query `?app_version_code=3&platform=android` atau header `X-App-Version-Code` (+ `X-App-Platform`) → hasilnya di blok `check`. |
—
|
| GET |
/api/v1/version/check
public
query: app_version_code
query: platform?
|
**CEK UPDATE (disarankan dipakai app).** PUBLIC — tanpa token. Versi app **WAJIB** dikirim → server langsung menjawab perlu/tidak perlu update. Bila `versionCode` app tidak dikirim → **400** `MISSING_APP_VERSION`. Bisa juga POST dgn body JSON (lebih aman bila versi app tidak ingin muncul di URL/log). |
app_version_code · number |
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/store
auth
|
Katalog paket utk app mobile (recyclerview). Hanya item ENABLED **dan** `show_in_app = 1` utk device milik customer. Termasuk info plan utk generate voucher. **price = harga jual (customers_store.price)** — dipakai sbg harga transaksi saat generate voucher (bandwidth_plan.price hanya acuan). is_promo utk badge Promo. ⚙️ Target tayang diatur di Backend → Customers → Customers Store → kolom **Tampil Di** (item bisa hanya tampil di hotspot publik / hanya di app). |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/voucher_template?device_id=RTR-XXX
auth
query: device_id?
|
Template voucher utk cetak: **logo** WiFi (path /uploads/voucher_logos/...), nama wifi, **ssid**, slogan, **nama paket (plan_name)**, kontak, cara konek, **organization_name** (branding usaha, tampil di bawah support) — dari customers_voucher_setup utk device milik customer, status enabled. Dipanggil app sebelum cetak voucher (setelah dapat katalog store & harga). Bila device belum disetup → data:null (app pakai template default). Logo disediakan sbg path relatif — app gabung dgn base_url utk full URL. |
—
|
| POST |
/api/v1/voucher_template?device_id=RTR-XXX
auth
query: device_id?
|
Update/edit template voucher (branding WiFi) utk device milik customer. Body multipart: wifi_name, **ssid**, slogan, **plan_name**, contact, cara_konek, status + file logo (opsional). Bila belum ada preset → dibuat otomatis dgn nilai default. |
—
|
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| POST |
/api/v1/profile/update
auth
|
Update profil: nama/alamat/timezone/bahasa; ganti password (wajib current_password). |
fullname? · stringaddress? · stringtimezone? · stringlanguage? · stringcurrent_password? · stringpassword? · stringpassword_confirm? · string |
| Method | Endpoint | Keterangan | Body / Query |
|---|---|---|---|
| GET |
/api/v1/router/device?identity=RTR-DIRFAGA01
public
query: identity
|
**CEK IDENTITAS** device dari system identity router. Dipakai halaman login (atau saat setup di router) utk memastikan `$(identity)` dikenali server. Mengembalikan info device (device_id, identity, connectivity) + `store_count` (jumlah paket aktif). Device tidak ditemukan/tidak aktif → 404 `DEVICE_NOT_FOUND`; param `identity` kosong → 400 `MISSING_IDENTITY`. |
—
|
| GET |
/api/v1/router/store?identity=RTR-DIRFAGA01
public
query: identity
|
**DAFTAR HARGA / STORE** (katalog paket yang dijual di device tsb) + **branding WiFi** (nama wifi/SSID/slogan/kontak/logo, `null` bila belum disetup). Hanya item `status=enabled` **DAN `show_in_hotspot=1`** — paket Gratis / khusus internal bisa disembunyikan dari halaman login publik (atur di Backend → Customers → Customers Store → kolom **Tampil Di**). Dipakai halaman login hotspot utk menampilkan pilihan paket & harga. `price_text` sudah diformat rupiah. `Cache-Control: public, max-age=30`. |
—
|
| GET |
/api/v1/router/voucher_usage?identity=RTR-DIRFAGA01&username=0213
public
query: identity
query: username
|
**PEMAKAIAN 1 VOUCHER**: kirim kode voucher (`username`) → status & sisa pemakaian. Berisi `user` (profil, disabled, valid-until, limit-uptime, limit-bytes-*), `limit_status` (status ok/habis_waktu/habis_kuota + rincian waktu & kuota), `usage` (sesi aktif: online, IP, MAC, hostname, uptime, session_time_left, bytes in/out), `cumulative` (pemakaian kumulatif), `masa_aktif` (aktivasi/kedaluwarsa kalender) & `summary` (siap tampil: `sisa_waktu`, `persen_waktu`, `kuota_terpakai`, `masa_aktif_berakhir`, dst). Sumber: router LIVE; bila router OFFLINE → fallback mirror DB (`source: "mirror"`, `router_online: false`). Tidak ditemukan → 404 `USER_NOT_FOUND`. `Cache-Control: no-store`. |
—
|
| Kode | Keterangan |
|---|---|
UNAUTHORIZED | Token tidak ada / tidak valid / kedaluwarsa (401) |
INVALID_CREDENTIALS | Email/HP atau password salah (401) |
FORBIDDEN | Akun customer tidak aktif (403) |
DEVICE_LOCKED | Tidak bisa mengganti device selama session aktif — logout dulu (403) |
NOT_FOUND | Data/device tidak ditemukan (404) |
VALIDATION_ERROR | Input tidak valid / wajib diisi (400) |
ROS_API_ERROR | Gagal komunikasi dgn RouterOS (502) |
ERROR | Server error (500) |
MISSING_IDENTITY | Parameter identity (system identity router) tidak dikirim (400) |
DEVICE_NOT_FOUND | Tidak ada device AKTIF dgn identity/device_id tsb (404) |
MISSING_USERNAME | Parameter username (kode voucher) tidak dikirim (400) |
USER_NOT_FOUND | Voucher/user hotspot tidak ada di device tsb (404) |
# 1) LOGIN → dapatkan token
POST https://tikhub.id/api/v1/auth/login
Content-Type: application/json
{ "identifier": "customer@mail.com", "password": "rahasia123" }
# 2) Lihat daftar device
GET https://tikhub.id/api/v1/devices
Authorization: Bearer tk_xxxxxxxxxxxxxxxxxxxxxxxx
# 3) PILIH device — WAJIB, SEKALI per session
POST https://tikhub.id/api/v1/devices/select
Authorization: Bearer tk_xxx
Content-Type: application/json
{ "device_id": "RTR-MT53ITIB" }
# 4) Cek info device + template voucher (branding utk cetak, termasuk logo)
GET https://tikhub.id/api/v1/devices/detail
Authorization: Bearer tk_xxx
# 5) Generate voucher
POST https://tikhub.id/api/v1/vouchers/generate
Authorization: Bearer tk_xxx
Content-Type: application/json
{ "profile": "Paket 1 Jam Masa Aktif 1 Hari", "quantity": 1, "prefix": "V" }
# 6) Lihat transaksi
GET https://tikhub.id/api/v1/transactions
Authorization: Bearer tk_xxx
# 7) LOGOUT
POST https://tikhub.id/api/v1/auth/logout
Authorization: Bearer tk_xxx