Skip to content

API Reference

francis edited this page Jan 3, 2026 · 1 revision

API Reference

This document provides comprehensive documentation for ncSender's REST API and WebSocket events. Use this reference to build integrations, custom clients, or automation tools.

Overview

  • Base URL: http://<host>:<port>/api
  • Default Port: 8090 (configurable in settings)
  • Authentication: None (local network access only)
  • Content-Type: application/json (unless specified otherwise)

REST API Endpoints

CNC Connection Management

List Serial Ports

GET /api/cnc/serial-ports

Returns available USB serial ports.

Response:

[
  { "path": "/dev/ttyUSB0", "manufacturer": "FTDI" },
  { "path": "/dev/ttyACM0", "manufacturer": "Arduino" }
]

Connect to CNC

POST /api/cnc/connect

Connect to CNC controller via USB or Ethernet.

Request Body:

// USB Connection
{ "port": "/dev/ttyUSB0", "baudRate": 115200 }

// Ethernet Connection
{ "ip": "192.168.1.100", "ethernetPort": 23 }

// Auto-connect (uses saved settings)
{}

Response:

{ "success": true, "message": "Connected to CNC" }

Disconnect from CNC

POST /api/cnc/disconnect

Response:

{ "success": true }

Get Connection Status

GET /api/cnc/status

Response:

{
  "connected": true,
  "port": "/dev/ttyUSB0",
  "baudRate": 115200,
  "machineState": { /* see Machine State section */ }
}

Send Command

POST /api/cnc/send-command

Send G-code or system command to CNC controller.

Request Body:

{
  "command": "G0 X10 Y20",
  "commandId": "optional-unique-id",
  "displayCommand": "G0 X10 Y20 (optional display text)",
  "meta": { "sourceId": "my-integration" }
}

Hex Commands: Use \xHH format (e.g., \x18 for soft reset)

Response:

{ "success": true, "commandId": "cmd-123456" }

G-code File Management

List Files

GET /api/gcode

Response:

{
  "tree": [
    { "name": "part.gcode", "type": "file", "size": 12345 },
    { "name": "projects", "type": "folder", "children": [...] }
  ]
}

Upload File

POST /api/gcode
Content-Type: multipart/form-data

Form Data:

  • file: Binary file (.gcode, .nc, .tap, .txt)

Response:

{ "success": true, "filename": "part.gcode" }

Load Temporary G-code (for plugins)

POST /api/gcode-files/load-temp

Request Body:

{
  "content": "G0 X0 Y0\nG1 X10 F1000\n...",
  "filename": "generated.gcode",
  "sourceFile": "original.gcode"
}

Get File Content

GET /api/gcode/file?path=part.gcode

Response:

{ "filename": "part.gcode", "content": "G0 X0 Y0\n..." }

Save File

POST /api/gcode/file/save

Request Body:

{ "path": "part.gcode", "content": "G0 X0 Y0\n..." }

Delete File

POST /api/gcode/file/delete

Request Body:

{ "path": "part.gcode" }

Create Folder

POST /api/gcode/folders

Request Body:

{ "path": "projects/new-folder" }

Move/Rename

POST /api/gcode/move

Request Body:

{ "sourcePath": "old-name.gcode", "destinationPath": "new-name.gcode" }

Download Current File

GET /api/gcode/current/download

Returns binary stream of currently loaded G-code.


G-code Job Execution

Start Job

POST /api/gcode-job

Request Body:

{ "filename": "part.gcode" }

Stop Job

POST /api/gcode-job/stop

Response:

{ "success": true, "pauseBeforeStop": 500 }

Analyze Line (for Resume)

POST /api/gcode-job/analyze-line

Request Body:

{ "lineNumber": 150 }

Response:

{
  "state": {
    "tool": 2,
    "spindleSpeed": 12000,
    "feedRate": 1000,
    "position": { "x": 10.5, "y": 20.3, "z": -5.0 }
  },
  "lineNumber": 150,
  "totalLines": 5000,
  "warnings": ["Machine is not homed"],
  "willPerformToolChange": true,
  "expectedTool": 2,
  "currentTool": 1,
  "resumeSequence": ["G21", "G90", "G54", "M6 T2", "S12000 M3", "G0 Z10"]
}

Start from Line

POST /api/gcode-job/start-from-line

Request Body:

{
  "filename": "part.gcode",
  "startLine": 150,
  "spindleDelaySec": 3,
  "approachHeight": 10,
  "plungeFeedRate": 500
}

Settings

Get All Settings

GET /api/settings

Get Specific Setting

GET /api/settings/:name

Update Settings (Partial)

PATCH /api/settings

Request Body:

{
  "connection": {
    "type": "ethernet",
    "ip": "192.168.1.100"
  }
}

Replace All Settings

POST /api/settings

Macros

List Macros

GET /api/macros

Response:

[
  {
    "id": "macro-123",
    "name": "Home All",
    "description": "Home all axes",
    "commands": "$H"
  }
]

Create Macro

POST /api/macros

Request Body:

{
  "name": "Park",
  "description": "Move to park position",
  "commands": "G53 G0 Z-5\nG53 G0 X0 Y0"
}

Execute Macro

POST /api/macros/:id/execute

Response:

{ "success": true, "commandsExecuted": 3 }

Update/Delete Macro

PUT /api/macros/:id
DELETE /api/macros/:id

Tools

List Tools

GET /api/tools

CRUD Operations

GET /api/tools/:id
POST /api/tools
PUT /api/tools/:id
DELETE /api/tools/:id

Bulk Update

PUT /api/tools

Request Body: Array of tool objects


Plugins

List Plugins

GET /api/plugins
GET /api/plugins/loaded

Enable/Disable Plugin

POST /api/plugins/:pluginId/enable
POST /api/plugins/:pluginId/disable

Plugin Settings

GET /api/plugins/:pluginId/settings
PUT /api/plugins/:pluginId/settings

Install Plugin

POST /api/plugins/install
Content-Type: multipart/form-data

Form field: plugin (ZIP file)

Install from URL

POST /api/plugins/install-from-url

Request Body:

{ "url": "https://github.com/user/repo/releases/download/v1.0/plugin.zip" }

Check for Updates

GET /api/plugins/:pluginId/check-update

Response:

{
  "hasUpdate": true,
  "currentVersion": "1.0.0",
  "latestVersion": "1.1.0",
  "downloadUrl": "https://..."
}

Firmware

Get Firmware Settings

GET /api/firmware
GET /api/firmware?refresh=true

Response:

{
  "version": "1.0",
  "firmwareVersion": "1.1f.20250407",
  "groups": {
    "0": { "id": 0, "name": "General" }
  },
  "settings": {
    "130": { "id": 130, "name": "$130", "value": "400", "unit": "mm" }
  }
}

Flash Firmware

POST /api/firmware/flash

Request Body:

{
  "hex": "base64-encoded-hex-file",
  "port": "/dev/ttyUSB0",
  "isDFU": false
}

Progress is broadcast via WebSocket events.


System

Health Check

GET /api/system/health

Response:

{ "status": "ok", "timestamp": "2024-01-15T10:30:00.000Z" }

Server State

GET /api/system/server-state

Logs

GET /api/system/logs
GET /api/system/logs/:filename
GET /api/system/logs/:filename/download

Probe Operations

Start Probe

POST /api/probe/start

Request Body:

{
  "probingAxis": "Z",
  "probingDistance": -50,
  "probingFeedRate": 100,
  "probingType": "tool-length"
}

Stop Probe

POST /api/probe/stop

Alarms

Get Alarm Description

GET /api/alarms/alarm/:id

Response:

{ "id": 1, "description": "Hard limit triggered" }

WebSocket API

Connect to WebSocket at: ws://<host>:<port>

Initial Connection

On connect, client receives:

{ "type": "client-id", "data": { "clientId": "client-123..." } }
{ "type": "server-state-updated", "data": { /* full state */ } }
{ "type": "gcode-updated", "data": { "filename": "...", "totalLines": 5000 } }

Events from Server

Server State Updates

{
  "type": "server-state-updated",
  "data": {
    "machineState": {
      "connected": true,
      "status": "idle",
      "tool": 1,
      "spindleSpeed": 0,
      "feedRateOverride": 100,
      "spindleSpeedOverride": 100,
      "MPos": { "x": 0, "y": 0, "z": 0 },
      "WPos": { "x": 0, "y": 0, "z": 0 },
      "homed": true,
      "alarms": []
    },
    "jobLoaded": {
      "filename": "part.gcode",
      "currentLine": 150,
      "totalLines": 5000,
      "status": "running",
      "progressPercent": 3.0,
      "estimatedSec": 1800,
      "remainingSec": 1746
    }
  }
}

Command Queued

{
  "type": "cnc-command",
  "data": {
    "id": "cmd-123",
    "command": "G0 X10",
    "displayCommand": "G0 X10",
    "status": "pending",
    "timestamp": "2024-01-15T10:30:00.000Z"
  }
}

Command Result

{
  "type": "cnc-command-result",
  "data": {
    "id": "cmd-123",
    "command": "G0 X10",
    "status": "success",
    "timestamp": "2024-01-15T10:30:01.000Z"
  }
}

G-code File Updated

{
  "type": "gcode-updated",
  "data": {
    "filename": "part.gcode",
    "totalLines": 5000,
    "size": 125000,
    "isTemporary": false
  }
}

Settings Changed

{
  "type": "settings-changed",
  "data": { /* changed fields */ }
}

Plugin Events

{
  "type": "plugins:tools-changed",
  "data": {
    "pluginId": "com.example.plugin",
    "action": "enabled"
  }
}

Firmware Flash Progress

{ "type": "flash:message", "data": { "message": "Erasing..." } }
{ "type": "flash:progress", "data": { "value": 50, "total": 100 } }
{ "type": "flash:error", "data": { "error": "Connection lost" } }
{ "type": "flash:end", "data": {} }

Commands to Server

Send G-code Command

{
  "type": "cnc:command",
  "data": {
    "command": "G0 X10 Y20",
    "commandId": "optional-id",
    "meta": { "sourceId": "my-app" }
  }
}

Start Continuous Jog

{
  "type": "jog:start",
  "data": {
    "axis": "X",
    "direction": 1,
    "distance": 10,
    "feedRate": 5000
  }
}

Stop Jog

{ "type": "jog:stop", "data": {} }

Close Job Progress Dialog

{ "type": "job:progress:close" }

Machine State Reference

The machineState object contains:

Property Type Description
connected boolean CNC connection status
status string idle, run, hold, alarm, door, check
tool number Current tool number
spindleSpeed number Current spindle RPM
feedRateCommanded number Commanded feed rate
feedRateOverride number Feed rate override % (0-200)
spindleSpeedOverride number Spindle override % (0-200)
MPos object Machine position { x, y, z, a?, b?, c? }
WPos object Work position { x, y, z, a?, b?, c? }
Ln number Currently executing line number (grblHAL)
homed boolean Homing status
isProbing boolean Probe operation in progress
isToolChanging boolean Tool change in progress
alarms array Active alarm codes

Error Handling

All endpoints return errors in this format:

{
  "error": "Error message description"
}

HTTP Status Codes:

  • 200 - Success
  • 400 - Bad Request (invalid parameters)
  • 404 - Not Found
  • 500 - Server Error

Rate Limits

No rate limits are enforced. However, for optimal performance:

  • Batch commands when possible
  • Use WebSocket for real-time updates instead of polling
  • Limit status polling to 100ms intervals minimum

Example Integration (Node.js)

const WebSocket = require('ws');

// Connect to ncSender
const ws = new WebSocket('ws://localhost:8090');

ws.on('open', () => {
  console.log('Connected to ncSender');

  // Send a G-code command
  ws.send(JSON.stringify({
    type: 'cnc:command',
    data: { command: 'G0 X10 Y10' }
  }));
});

ws.on('message', (data) => {
  const msg = JSON.parse(data);

  if (msg.type === 'server-state-updated') {
    console.log('Position:', msg.data.machineState.WPos);
  }

  if (msg.type === 'cnc-command-result') {
    console.log('Command result:', msg.data.status);
  }
});

See Also

Clone this wiki locally