TikHub Customer API (Mobile / Android)

Dokumentasi publik — untuk pengembang aplikasi mobile. Semua endpoint di bawah base URL di bawah.

v1.0
Base URL (production)
https://tikhub.id/api/v1
Autentikasi
Authorization: Bearer <token>
Format Respons
JSON — { success, message, data, code }
Header Identitas Aplikasi (wajib di setiap request)
Kirim di SETIAP request agar versi aplikasi tercatat di audit log server (Audit API Logs).
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
Prosedur — Bagaimana API Bekerja

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.

1 Login — Dapatkan Token
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).

2 Lihat Daftar Device
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.

3 Pilih Device (WAJIB, sekali per session)
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).

4 Cek Info Device + Template Voucher (opsional)
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.

5 Ambil Bandwidth Profile (Paket)
GET /api/v1/profiles auth

Daftar paket (profile) utk dipilih user. device_id boleh kosong → memakai selected device.

6 Generate Voucher
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.

7 Lihat Transaksi / Laporan Penjualan
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.

8 Cek Statistik Singkat (opsional)
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.

9 Logout — Keluar Session
POST /api/v1/auth/logout auth

Menonaktifkan token & menghapus pilihan device. WAJIB utk bisa memilih device LAIN: logout → login → pilih device baru.

Catatan Penting
  • Satu session (login) hanya boleh memilih SATU device.
  • TIDAK bisa pindah/ganti device selama session aktif — POST /api/v1/devices/select akan menolak dgn kode DEVICE_LOCKED (403) bila mencoba memilih device lain.
  • Utk mengganti device: LOGOUT dulu (POST /api/v1/auth/logout) utk menghapus session & pilihan device, lalu LOGIN kembali, kemudian pilih device baru.
  • Pilihan device tersimpan PER SESSION (token). Setelah logout, pilihan hilang & harus pilih lagi saat login baru.
  • device_id di endpoint profiles/vouchers bersifat OPSIONAL — jika tidak dikirim, otomatis memakai selected device.
  • Endpoint GET /api/v1/version & GET|POST /api/v1/version/check bersifat PUBLIC (tanpa token) — dipakai app utk cek update sebelum login.
  • Cek update (WAJIB diterapkan app): panggil GET /api/v1/version/check DENGAN menyertakan versionCode app (?app_version_code=3 atau header X-App-Version-Code: 3). update_required=true → tampilkan dialog update + buka latest.download_url; mandatory=true → update WAJIB (blokir pemakaian app sampai di-update). versionCode app >= latest.versionCode → lanjut normal.
  • Kirim header X-App-Package / X-App-Platform / X-App-Version-Code / X-App-Version-Name di SETIAP request (auth maupun tidak) agar versi app tercatat di Audit API Logs.
  • 📍 LOGO VOUCHER (utk cetak voucher) — variabel `logo` (URL `/uploads/voucher_logos/<file>`) TERSEDIA di 4 tempat: (1) `POST /api/v1/devices/select` → `data.voucher_template.logo`; (2) `GET /api/v1/devices/detail` → `data.voucher_template.logo`; (3) `GET /api/v1/devices` → tiap item `data[].logo` (nama file) & `data[].logo_url`; (4) `POST /api/v1/auth/login` & `GET /api/v1/auth/me` → `customer.logo` & `customer.logo_url`. Bila customer belum upload logo → `null`. App disarankan: download logo SEKALI dari `logo_url` lalu simpan di local storage keyed by `device_id` (pakai file lokal utk cetak — cepat & offline).
  • 📡 API PUBLIK utk LOGIN PAGE hotspot MikroTik (±/api/v1/router/*) — tanpa token. Device dikenali dari SYSTEM IDENTITY router: parameter `identity` = `$(identity)` di halaman login (sama dgn kolom `devices.identity`, mis. `RTR-DIRFAGA01`); `device_id` (mis. `RTR-MU0INEFR`) juga diterima sebagai cadangan. Dipakai utk menampilkan DAFTAR HARGA/PAKET (store) & PEMAKAIAN VOUCHER (sisa waktu/kuota) langsung di halaman login hotspot.
  • 👁️ TARGET TAYANG item store (customers_store) — atur di Backend → Customers → Customers Store → kolom **Tampil Di** (klik badge untuk cepat): `status` = saklar utama (Disabled → tidak tampil di mana pun) · `show_in_app` → catalog `GET /api/v1/store` (app mobile) · `show_in_hotspot` → `GET /api/v1/router/store` (hotspot login page PUBLIK). Contoh: paket **Gratis** / **khusus internal** → matikan `show_in_hotspot` supaya tidak tampil ke umum, tapi tetap bisa dijual/dicetak operator di app mobile.
  • 🌐 CORS: semua respons `/api/v1/router/*` memuat `Access-Control-Allow-Origin: *` (hanya GET, OPTIONS dijawab 204) supaya halaman login yang di-host DI ROUTER (origin berbeda) bisa fetch ke `https://tikhub.id`. Tidak ada cookie/kredensial — jangan pakai endpoint ini utk data sensitif.
  • ⚙️ Di login.html, variabel MikroTik `$(...)` HANYA diganti pada file .html yang dilayani hotspot — file .js eksternal TIDAK diproses. Jadi tulis `var IDENTITY = "$(identity)";` di dalam login.html, lalu pakai di script (boleh inline atau file .js): fetch(`${BASE}/api/v1/router/store?identity=${IDENTITY}`).
  • 📅 FILTER RENTANG/PERIODE TRANSAKSI (`/api/v1/transactions` & `/summary`) — pilih SALAH SATU: CUSTOM `from`/`start_date` → `to`/`end_date` · BULAN `month=YYYY-MM` · TAHUN `year=YYYY` · PRESET `period=today|yesterday|7d|30d|this_month|last_month|this_year|last_year|all` (+ alias Indonesia: hari_ini, kemarin, bulan_ini, bulan_lalu, tahun_ini, tahun_lalu, semua). Semua INKLUSIF dan mengikuti TANGGAL SERVER (WIT / UTC+9). Format `YYYY-MM-DD` (tanggal saja = 00:00:00 s/d 23:59:59) atau `"YYYY-MM-DD HH:MM:SS"`. Prioritas: from/to > month > year > period. Tidak valid → 400 VALIDATION_ERROR. Contoh: `?month=2026-09`, `?year=2026`, `?period=this_month`.
  • 🗓️ DAFTAR PERIODE YANG BISA DIPILIH (picker app): `GET /api/v1/transactions/periods` → `presets` (preset + rentang tanggalnya), `months` (bulan yg ada transaksi + jumlah & omzet), `years` (tahun yg ada transaksi), plus `first_at`/`last_at` (batas pilihan CUSTOM) — sehingga app bisa menampilkan menu Custom / Bulan / Tahun tanpa menebak.
  • 🔐 AKSES TRANSAKSI per role: owner & administrator → seluruh transaksi ORGANISASI (semua device miliknya, boleh filter device_id); operator → HANYA transaksi device yang di-assign ke dirinya (parameter device_id dari app diabaikan). Ketiga role boleh memanggil daftar, summary, dan detail (whitelist OPERATOR_ALLOWED).
Autentikasi (Login / Logout / Me)
MethodEndpointKeteranganBody / 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 · string
password · 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 · string
email? · string
POST /api/v1/auth/forgot/verify public Verifikasi OTP reset password → balikin `reset_token` (sekali pakai, berlaku sesuai OTP 5 menit). identifier · string
otp · 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 · string
reset_token · string
new_password · string
Role User Customer (Owner / Administrator / Operator)
MethodEndpointKeteranganBody / 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. —
Device Selector (Pilih Device)
MethodEndpointKeteranganBody / 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). —
Bandwidth Profile (CRUD)
MethodEndpointKeteranganBody / 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 · string
name · string
rate? · string
burst? · string
session_timeout? · string
timebase? · string
quota_mb? · number
price? · number
masa_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 · string
name · string
rate, 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 · string
device_id · string
name · string
rate, 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 · string
id · string
name? · 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). —
Voucher (Generate & Cetak)
MethodEndpointKeteranganBody / 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? · string
store_id? · number
profile? · string
quantity? · number
prefix? · 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`. —
Transaksi (Penjualan) — Custom / Bulan / Tahun
MethodEndpointKeteranganBody / 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. —
Statistik Cepat & Versi (Quick Stats / Version)
MethodEndpointKeteranganBody / 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
Store (Katalog Paket)
MethodEndpointKeteranganBody / 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). —
Voucher Template (Branding WiFi)
MethodEndpointKeteranganBody / 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. —
Profil Customer (Update)
MethodEndpointKeteranganBody / Query
POST /api/v1/profile/update auth Update profil: nama/alamat/timezone/bahasa; ganti password (wajib current_password). fullname? · string
address? · string
timezone? · string
language? · string
current_password? · string
password? · string
password_confirm? · string
Router / Hotspot MikroTik — LOGIN PAGE (PUBLIK, tanpa token)
MethodEndpointKeteranganBody / 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 Error
KodeKeterangan
UNAUTHORIZEDToken tidak ada / tidak valid / kedaluwarsa (401)
INVALID_CREDENTIALSEmail/HP atau password salah (401)
FORBIDDENAkun customer tidak aktif (403)
DEVICE_LOCKEDTidak bisa mengganti device selama session aktif — logout dulu (403)
NOT_FOUNDData/device tidak ditemukan (404)
VALIDATION_ERRORInput tidak valid / wajib diisi (400)
ROS_API_ERRORGagal komunikasi dgn RouterOS (502)
ERRORServer error (500)
MISSING_IDENTITYParameter identity (system identity router) tidak dikirim (400)
DEVICE_NOT_FOUNDTidak ada device AKTIF dgn identity/device_id tsb (404)
MISSING_USERNAMEParameter username (kode voucher) tidak dikirim (400)
USER_NOT_FOUNDVoucher/user hotspot tidak ada di device tsb (404)
Contoh Request (cURL)
# 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