API Reference¶
The authoritative, machine-readable contract is openapi.yaml.
Read it rendered in the full reference or load it into any OpenAPI viewer. This
page is a human-friendly index grouped by capability.
All endpoints except GET / and POST /api/connect require a Bearer token
(see Authentication). Base URL: http://localhost:19520
(LightBurn) or 19521 (MillMage) — these ports are fixed per product. Replace
localhost with the host's address when the application has network access
enabled; POST /api/connect remains localhost-only regardless.
With more than one copy of the same product running, the port is served by the most recently focused window — see Overview.
Pairing & service (no auth)¶
| Method & path | Description |
|---|---|
GET / |
Placeholder HTML page |
POST /api/connect |
Pair a localhost application; returns a shared secret |
state capability — read-only machine & job state¶
| Method & path | Description |
|---|---|
GET /api/status |
Connection status and device capabilities |
GET /api/position |
Machine and workpiece coordinates |
GET /api/jog/settings |
Current jog distance/speed settings |
GET /api/goto/saved |
Saved positions from the device profile |
GET /api/units |
Current display units |
GET /api/events |
Server-Sent Events stream of state changes |
GET /api/events/poll |
Latest state snapshot (polling fallback) |
project capability — read-only project data¶
| Method & path | Description |
|---|---|
GET /api/project |
Project metadata: filename, units, workspace, device (including laser source capabilities) |
GET /api/layers |
All 32 layer definitions |
GET /api/cuts |
Cut settings for all layers or operations (product-specific) |
GET /api/cuts/{index} |
A single cut entry by flat index |
GET /api/material-library |
Loaded material / operations library |
GET /api/overlay |
Camera overlay image as PNG (LightBurn only) |
GET /api/overlay/metadata |
Overlay size, workspace placement and change token |
upload capability — submit files¶
| Method & path | Description |
|---|---|
POST /api/file/upload |
Import a file into the current project (supports placement headers) |
POST /api/file/open |
Replace the current project with the uploaded file |
See Uploading files for the request body, X-Filename, and the
placement headers (X-Position-X/Y, X-Origin, X-Group-Shapes).
project_write capability — change project data¶
| Method & path | Description |
|---|---|
POST /api/cuts/{index} |
Partial update of one cut entry; returns the updated entry |
See Cut settings for the fields each product accepts, how
changes are validated and applied, and the 409 returned while the cut editor
is open.
Conventions¶
- Auth:
Authorization: Bearer <token>. Every authorization failure returns a401with an undifferentiated{"error":"Unauthorized"}body — missing, invalid, expired, revoked, or outside your granted capability. The reasons are deliberately indistinguishable; don't branch on them. A request from off-machine while network access is off is a different case: nothing is listening on that address, so the connection is refused at the TCP layer rather than answered with a401— see Authentication. - Units: positions (
/api/position, thepositionevent) and the/api/projectworkspaceare always in mm. LightBurn cut values, the MillMagetoolblock, and jog settings use the user's display units — read those fromGET /api/units, which reports the speed unit asunitsand the distance unit asdistance_units. The two are independent: the application supports modes that pair inch distances with metric speeds, so never infer one from the other. MillMage operationsettingsare always mm and mm/s. (/api/projectunits.distanceis a translated UI label for display only — don't parse it.) - Connection state:
connected(onGET /api/statusand theconnectionevent) means a device link is open right now. Ruida and some other non-GCode controllers connect just in time and disconnect once the transfer finishes, soconnectedisfalseat rest for a perfectly healthy laser and toggles around activity. It is not a presence or health check — don't show it as a fault. How long a link is held open varies by controller and by how the device is connected. - Job state on Ruida:
job.stateis alwaysidleandprogressis never present — the controller runs a job on its own once the file is sent, and the application doesn't track it. On Ruida,idledoesn't mean the machine is free.device.laser.controlleronGET /api/projecttells you which controller is attached. - Optional fields: a field the application can't report is omitted rather
than zeroed — for example an axis the controller doesn't report, or job
progresswhile idle or on controllers that don't report it. Treat absence as "unknown". - Async import: uploads return
202 Acceptedimmediately; the result arrives later as afile_importedevent onGET /api/events. For/api/file/openitssuccessis reliable only for native project files; other formats reportfalseeven when they opened — see Uploading. - Events: the SSE stream opens with a
:connectedcomment. "On change" events aren't replayed to a new subscriber, so callGET /api/events/pollonce after connecting to get the current state. - Partial updates:
POST /api/cuts/{index}changes only the fields in the body and validates the whole body first — on any error nothing changes. - Product differences:
GET /api/cuts,POST /api/cuts/{index}andGET /api/material-libraryuse product-specific shapes — dispatch on theproductfield. The overlay endpoints are LightBurn-only and return404on MillMage. - Machine differences: LightBurn cut entries carry a
profileofgalvo,gantryorunknown. Onkind: "normal"entries that comes with exactly one matchingparams.galvo/params.gantryblock;kind: "image"entries carry theprofilebut no block. Switching the active device changes the shape for an unchanged project, so don't cache it — see Cut settings. - Binary responses:
GET /api/overlayreturnsimage/pngon success butapplication/jsonon error — branch on the status code, not the content type.
Stability¶
Endpoint and field details may change between application releases until versioning ships — see Versioning. Only documented behaviour is supported; undocumented responses may change without notice.