Hallo Stroke

API Reference

Complete REST API endpoint reference.

All routes are under /api. Protected routes require Authorization: Bearer <JWT>. Admin routes additionally require role == "admin". Super-admin routes require a role: "superadmin" JWT.

Auth

Public

MethodPathBodyReturns
POST/login{username, password}{access_token, refresh_token}
POST/register{username, email?, password, nik(16), nama_ktp, nama_samaran, nomor_hp, role?, preferences?}{access_token, refresh_token}
POST/refresh{refresh_token}{access_token}
POST/auth/check-username{username}{available, message}
GET/send-verification-code?phone=sends WhatsApp reset link
POST/update-password{code, new_password(min6)}{message}
POST/superadmin/login{username, password}{access_token, message}

Protected (JWT required)

MethodPathDescription
POST/logoutClears stored refresh token
GET/profileReturns user (NIK decrypted)
PUT/profileEdit profile (multipart: nik, nama_ktp, nama_samaran, nomor_hp, email, password, preferences, role_ids, image)
GET/users/:idRoles for the authenticated user
POST/caregiver/patientsBody {patient_id} — caller must have pendamping role
GET/caregiver/patientsList the caller's patients
GET/patient/caregiversList the caller's caregivers
GET/patientsAll users with pasien role
GET/caregiversAll users with pendamping role
DELETE/caregiver/patients/:idRemove a patient link

Roles

MethodPathBodyNotes
GET/rolesList all roles
POST/roles{name, is_editable}
GET/roles/:id
PUT/roles/:id{name, is_editable?}Non-editable roles rejected
DELETE/roles/:idNon-editable roles rejected
POST/admins/:id/roles{role_ids:[]}ON CONFLICT DO NOTHING
GET/users/:id/rolesRoles for a user
DELETE/admins/:id/roles{role_ids:[]}

Kategori (dynamic content categories)

MethodPathBody
POST/kategori{nama_kategori}
GET/kategori
PUT/kategori/:id
DELETE/kategori/:id

Faskes (health facilities)

MethodPathQueryNotes
GET/faskes/nearbylat, lng, radius?(m, default 5000)Haversine + Google Places fallback; in-memory grid cache (4h, 1km hit radius)
GET/faskes/{results, status}
GET/faskes/locationlat, lngDB Haversine within 50 km
GET/faskes/searchkeywordLIKE on nama
GET/faskes/:id:id is Google place_id

Admin: POST/PUT/DELETE /faskes[/:id].

Forum

Public read uses OptionalJWT (populates is_liked/is_saved if logged in).

MethodPathAuthDescription
GET/forum/categoriesoptionalList categories
GET/forum/threads?category_id=optionalList threads
GET/forum/threads/:idoptionalThread detail + nested replies + counts
POST/forum/threadsJWTCreate (multipart: category_id, title, content, use_pseudonym, image) → fires WhatsApp broadcast
PUT/forum/threads/:idJWTEdit (multipart)
DELETE/forum/threads/:idJWTOwner only
POST/forum/threads/:id/replyJWTReply (multipart: content, use_pseudonym, parent_id?, image) → notifies thread creator
POST/forum/threads/:id/likeJWTToggle → {is_liked}
POST/forum/threads/:id/saveJWTToggle → {is_saved}
DELETE/forum/replies/:idJWTOwner only
POST/forum/replies/:id/likeJWTToggle
POST/forum/replies/:id/saveJWTToggle
PUT/forum/replies/:idJWTEdit (multipart)

Articles

MethodPathAuthDescription
GET/articles/Scrape Kemenkes live → [{title, url, is_saved}]
GET/articles/detail?url=Scrape full article by URL
GET/articles/allDB-backed list
GET/articles/search?title=
GET/articles/url?url=
GET/articles/:idNumeric DB ID
POST/articles/saveJWTBody {url, title}{is_saved}
GET/articles/savedJWT

Admin: POST/PUT/DELETE /articles[/:id] (multipart add).

YouTube

MethodPathAuthDescription
GET/youtube/videosDB list
GET/youtube/videos/:idDB by ID
GET/youtube/videos/:id/detailLive YouTube API
GET/youtube/channel/:channelIdLatest 20
GET/youtube/search?q=Search
POST/youtube/saveJWTBody {video_id, title, channel_title?, thumbnail_url?}{is_saved}
GET/youtube/savedJWT

Admin: POST/PUT/DELETE /youtube/video[/:id].

Komunitas

MethodPathAuth
GET/komunitas/
GET/komunitas/:id

Admin: POST/PUT/DELETE /komunitas[/:id] (multipart with image).

Dokter

MethodPathAuth
GET/dokter/
GET/dokter/:id

Admin: POST/PUT/DELETE /dokter[/:id].

Pengingat (reminders)

See Backend Reminders for the scheduler. All protected (JWT).

MethodPathBody / Query
POST/pengingat/{tipe(makan/terapi/kontrol), judul, waktu(RFC3339), timezone?, details(json)}
POST/pengingat/obat{judul, timezone?, details:{nama_obat, frekuensi, jadwal:[{jam, jumlah, satuan}], aturan}}
GET/pengingat/?tipe=optional tipe filter
GET/pengingat/:id
PUT/pengingat/:idpartial update
DELETE/pengingat/:id

Push notifications

MethodPathBodyNotes
POST/push/subscribe{endpoint, keys:{p256dh, auth}, user_id?}no JWT
POST/push/send{user_id, payload:{title, body, url?}}no JWT

Logs

MethodPathBodyNotes
POST/log/user-logLogUserasync-queued, returns 202
POST/log/admin-logLogAdminasync-queued, returns 202

Admin

All require role == "admin".

MethodPathDescription
GET/admins/List admins
POST/admins/Create admin (multipart: email, password, nama_ktp, role?, nomor_hp?, image)
GET/admins/usersList all users
GET/admins/users/:idUser detail (NIK decrypted)
PUT/admins/users/:id{is_verified?, role_ids?}
GET/admins/caregiver-patient/allAll caregiver–patient relations
GET/admins/caregiver-patient?caregiver_id=Caregiver's patients
POST/admins/caregiver-patient{caregiver_id, patient_id} (validates pendamping + pasien)
DELETE/admins/caregiver-patient{caregiver_id, patient_id}
GET/admins/:username
PUT/admins/:idEdit admin (multipart)
DELETE/admins/:idDelete admin

Super-admin

All require a role: "superadmin" JWT, re-verified in each handler.

MethodPathDescription
POST/superadmin/queryBody {query} — arbitrary SQL
GET/superadmin/tablesList tables
GET/superadmin/tables/:tableNameTable data
GET/superadmin/tables/:tableName/exporttext/csv
POST/superadmin/query/exportBody {query} → CSV

Arbitrary SQL

/superadmin/query executes arbitrary SQL. It is the most privileged endpoint in the system and should be tightly network-restricted in production.

On this page