← Back to SQ Manager

API reference

SQ Manager runs an HTTP server on the Android device you install it on. The dashboard, the ticket kiosk, the queue display and the workstation all talk to that server through a small JSON over HTTP API. This page documents the public endpoint shape so you can write a custom display, a third-party reporting tool, or a kiosk skin against it.

Read this first. The on-device server is designed to be reached from another device on the same local network (LAN / Wi-Fi), not from the public internet. There is no built-in cloud relay. Expose the port to the public internet at your own risk and never without authentication.

Base URL & conventions

The default port is 8443 on the device that runs the app. The base URL therefore looks like:

http://192.168.0.42:8443/

You can change the port in the in-app Settings → Virtual Server screen. The same host serves the dashboard HTML at / and the API under the prefixes below. All API responses are application/json; charset=utf-8 unless documented otherwise. Field names use camelCase. Timestamps are ISO 8601 strings in the device's local time zone.

Authentication

Every endpoint that reads queue data, calls the next ticket, or modifies settings requires an authenticated dashboard session. The default auth flow is:

  1. POST /read/login with a JSON body {"username": "...", "password": "..."}. On success, the response sets a session cookie.
  2. The browser (or your script) keeps the cookie and re-uses it on every subsequent call.
  3. Idle sessions expire after 30 minutes of no activity.

A small number of endpoints are exempted from the login requirement because they are needed before the login screen can render (for example, the language list and the build version). See Exempted endpoints below.

Endpoint groups

The server distinguishes five route groups by URL prefix. The prefix tells the server which handler to dispatch to and which response shape to use.

/read/ - reads

Read-only lookups. GET by default; some accept POST for backward compatibility with the dashboard's older XHR wrapper.

/read/login-setting

GET /read/login-setting

Returns the public, non-secret parts of the login screen config: available languages, app build, device nickname, allowed-username hint.

/read/login

POST /read/login

Authenticates a dashboard user. Body: {"username": "string", "password": "string"}. On success returns {"ok": true, "displayName": "...", "permissions": ["VIEW","CALL","..."]} and sets a session cookie. On failure returns 401 with {"ok": false, "reason": "invalid_credentials"}.

/read/queue-display-setting

GET /read/queue-display-setting

Returns the queue-display screen configuration: theme, marquee text, language pair, font size, idle screen on/off.

/read/ticket-kiosk-setting

GET /read/ticket-kiosk-setting

Returns the ticket-kiosk configuration: service list (with English / Bahasa Malaysia labels), printer selection, footer text, idle timeout.

/read/workstation-setting

GET /read/workstation-setting

Returns the workstation (counter) configuration: counter list, services this counter serves, the "next" call strategy (FIFO / priority / VIP).

/read/web-socket-port

GET /read/web-socket-port

Returns {"port": 8444}. The dashboard opens a WebSocket on that port for live ticket and call updates.

/trigger/ - state changes

Trigger endpoints perform a side-effect on the device (issue a ticket, call the next one, mark a customer as done, reset the system). They are typically POST and always require an authenticated session.

/trigger/testing

POST /trigger/testing

Diagnostic ping. Body: {"nonce": "..."}. Response: {"ok": true, "echo": "..."}. Used by the dashboard's "is the server alive" check.

/trigger/system-reset

POST /trigger/system-reset

Wipes all live queue state for the current business day (issued tickets, call log, served count). Does not delete configuration or dashboard users. Requires the ADMIN permission. Response: {"ok": true, "resetAt": "2026-10-11T08:00:00+08:00"}.

/trigger/app-version

POST /trigger/app-version

Returns the running versions of every installed SQ Manager module (system, dashboard, virtual kiosk, ticket kiosk, queue display). Used by the in-app "About → Versions" page.

/trigger/update-htdocs

POST /trigger/update-htdocs

Asks the device to download and install a newer copy of a single web component (for example, the dashboard). Body: {"htdocs_type": "dashboard", "download_url": "https://...", "file_name": "..."}. Requires the ADMIN permission. Response is streamed back over the same connection with progress events.

Other trigger endpoints cover the rest of the queue workflow: /trigger/ticket-issue, /trigger/ticket-call, /trigger/ticket-recall, /trigger/ticket-skip, /trigger/ticket-served, /trigger/ticket-no-show, /trigger/ticket-transfer, /trigger/feedback-submit. Each takes a JSON body and returns {"ok": true, ...} or {"ok": false, "reason": "..."}.

/enum/ - enumerations

Returns the fixed enumerations the dashboard needs to render dropdowns: services, counters, departments, ticket prefixes, languages, permission levels, ticket states, and so on. GET only. Responses are short and cacheable on the client.

/datapool/ - shared queue state

The datapool endpoints expose the live, shared state of the queue. They are read by the WebSocket subscriber that the dashboard opens after login and by the queue-display screen. The two you will touch most often are:

  • /datapool/queue-data - the full snapshot of currently-issued tickets, served tickets, no-shows, and per-counter call log. Returned as a single JSON document and re-sent (in delta form) on every state change.
  • /datapool/queue-data/recent - the last N served tickets, for the served-today wall display.

/raw/ - raw assets

Returns a raw binary asset, not JSON. Today the only asset served this way is /raw/voice-module which streams the bundled TTS voice prompt that the workstation plays when a ticket is called. The response is audio/wav or audio/ogg depending on the device locale.

Exempted (no-auth) endpoints

The following endpoints are exempted from the login requirement by BlueprintExceptionApi, so the login screen can render before a user has signed in:

/read/login-setting
/read/login
/trigger/testing
/trigger/system-reset
/trigger/app-version
/trigger/update-htdocs
/read/queue-display-setting
/read/ticket-kiosk-setting
/read/workstation-setting
/read/web-socket-port
/raw/voice-module
/datapool/queue-data

Even though these endpoints are exempted from the access-token check, they still validate input and apply the same permission rules as authenticated calls. /trigger/system-reset and /trigger/update-htdocs in particular still require a logged-in dashboard user with the ADMIN permission - "exempted" here means "exempted from the auth check at the edge", not "open to the public".

Error responses

The server returns standard HTTP status codes plus a small JSON body for errors. Examples:

400 Bad Request    {"ok": false, "reason": "missing_field", "field": "username"}
401 Unauthorized   {"ok": false, "reason": "invalid_credentials"}
403 Forbidden      {"ok": false, "reason": "permission_denied", "need": "ADMIN"}
404 Not Found      {"ok": false, "reason": "no_such_endpoint"}
405 Method Not Allowed  (plain text)
429 Too Many Requests {"ok": false, "reason": "rate_limited", "retryAfterMs": 1000}
500 Server Error   {"ok": false, "reason": "internal", "traceId": "..."}

Versioning

The on-device API does not yet ship with a version prefix. New fields are added to existing response objects in a backward-compatible way (additive only). Breaking changes are signalled by a X-SQM-Api-Version response header that the server starts sending one minor release before the breaking change takes effect; clients that understand the header can refuse to talk to an incompatible server. Until that header starts shipping, the safest assumption is that every release may add fields but will not rename or remove them.

Looking for the dashboard's JavaScript? It lives in app/src/main/assets/initial_dashboard_htdocs/ in the project tree. Looking for a way to subscribe to live updates? Open a WebSocket on the port returned by /read/web-socket-port after login - the same JSON delta format as the REST datapool is sent on every change.