Skip to main content

ControlForge REST API Guide (OpenAPI 3.1)

James M. Belcher Founder, JMB Technical Services LLC June 2026 | ControlForge v1.0.1064


1. Overview

ControlForge exposes 407 operations across 336 paths (52 subsystem tags) for full control of the PLC runtime — programs, tasks, variables, protocols, diagnostics, clustering, fleet management, and more. Every operation available in the IDE is also available via HTTP.

Access Points

URLService
http://host:port/api/spec-uiInteractive API docs (OpenAPI 3.1)
http://host:port/api/openapi.jsonOpenAPI 3.1 spec (JSON)
http://host:port/api/*REST API
ws://host:port/wsWebSocket (real-time variable push)
http://host:port/ide/Web IDE
http://host:port/nodered/Node-RED (if enabled)

Interactive API Docs

Open http://localhost:8082/api/spec-ui in a browser. Every endpoint is documented with request/response schemas, parameter descriptions, and a "Try it out" button for live testing.

The API surface is described by a single OpenAPI 3.1 spec served at http://localhost:8082/api/openapi.json. The spec is generated by huma directly from the typed handler input/output structs, so it always matches the running build. (A gin engine still hosts the HTTP routes internally, but the documented contract for every endpoint is the huma OpenAPI spec — not the gin handlers.)


2. API Endpoint Groups

Programs (10)

MethodEndpointDescription
GET/api/programsList all programs
POST/api/programsCreate or update program
GET/api/programs/{name}Get program source
DELETE/api/programs/{name}Delete program
POST/api/programs/{name}/validateSyntax check without deploy
POST/api/programs/reloadReload all programs
POST/api/programs/clearRemove all programs
GET/api/project/exportExport all as JSON
POST/api/programs/importImport from JSON
GET/api/project/hashCurrent program hash

Tasks (9)

MethodEndpointDescription
GET/api/tasksList all tasks with metrics
POST/api/tasksCreate task
GET/api/tasks/{name}Task detail + scan stats
PUT/api/tasks/{name}Update task config
DELETE/api/tasks/{name}Delete task
POST/api/tasks/{name}/startStart task
POST/api/tasks/{name}/stopStop task
POST/api/tasks/{name}/reloadReload task programs
POST/api/tasks/{name}/downloadDownload task project

Variables (5)

MethodEndpointDescription
GET/api/variablesList all variables with values
GET/api/variables/{name}Read single variable
PUT/api/variables/{name}Write variable ({"value": ...})
POST/api/variables/bulkBulk read ({"names": [...]})
GET/api/variables/metaList variables with metadata

Runtime (9)

MethodEndpointDescription
GET/api/runtimeRuntime status
GET/api/statusDetailed status
POST/api/runtime/startStart runtime
POST/api/runtime/stopStop runtime
POST/api/runtime/pausePause execution
POST/api/runtime/resumeResume execution
POST/api/runtime/restartStop + reload + start
GET/api/runtime/downloadDownload project as .goplc
POST/api/runtime/uploadUpload and apply .goplc

System (7)

MethodEndpointDescription
GET/api/infoVersion, hostname, OS, uptime
GET/api/statsMemory, goroutines
GET/api/diagnosticsFull diagnostic dump
GET/api/faultsActive task faults
GET/api/capabilitiesLanguage features and data types
POST/api/system/shutdownGraceful shutdown (SIGTERM)
POST/api/system/restartRe-exec process

AI (5)

MethodEndpointDescription
GET/api/ai/statusAI availability, provider, model
POST/api/ai/chatChat with AI assistant
POST/api/ai/controlAutonomous tool-calling (blocking)
POST/api/ai/control/streamAutonomous tool-calling (SSE)
GET/api/ai/capabilitiesSystem prompt stats

HMI (6)

MethodEndpointDescription
GET/api/hmi/pagesList HMI pages
POST/api/hmi/pagesCreate HMI page
GET/api/hmi/pages/{name}Get page content
PUT/api/hmi/pages/{name}Update page
DELETE/api/hmi/pages/{name}Delete page
GET/hmi/{name}Serve HMI page to browser

Debug (41)

MethodEndpointDescription
GET/api/debug/runtime/modulesList debug modules and levels
POST/api/debug/levelSet module log level
GET/api/debug/runtime/bufferRead log ring buffer
POST/api/debug/fileEnable file logging
DELETE/api/debug/fileDisable file logging
POST/api/debug/db/sqliteEnable SQLite logging
POST/api/debug/db/postgresEnable PostgreSQL logging
GET/api/debug/db/queryQuery log database
POST/api/debug/influxEnable InfluxDB logging
GET/POST/DELETE/api/debug/step/*Statement-level debugger (breakpoints, step, state)
......(41 total debug endpoints)

Cluster (9) + Cluster Ops (10)

MethodEndpointDescription
GET/api/cluster/membersList cluster members
POST/api/cluster/enablePromote to boss
POST/api/cluster/disableRevert to standalone
POST/api/cluster/minionsSpawn minion
DELETE/api/cluster/minions/{name}Remove minion
GET/api/cluster/dynamicCluster status
ANY/api/cluster/{name}/*Proxy to minion API
POST/api/cluster-ops/exportExport cluster bundle
POST/api/cluster-ops/importImport cluster bundle
POST/api/cluster-ops/reload-allReload all nodes

Fleet (16)

MethodEndpointDescription
GET/api/fleet/discovermDNS discovery scan
GET/api/fleet/nodesList fleet nodes
PUT/api/fleet/nodes/{id}Add/update node
DELETE/api/fleet/nodes/{id}Remove node
POST/api/fleet/nodes/{id}/pollPoll node
POST/api/fleet/nodes/{id}/configPush config
GET/api/fleet/nodes/{id}/snapshotsNode snapshots
POST/api/fleet/nodes/{id}/pushPush snapshot
POST/api/fleet/push-bulkPush to multiple nodes
GET/api/fleet/driftDrift detection
POST/api/fleet/snapshots/collectCollect from all nodes
POST/api/fleet/snapshots/exportExport snapshots
POST/api/fleet/snapshots/purgePurge old snapshots
POST/api/fleet/template/renderRender config template

Snapshots (4)

MethodEndpointDescription
GET/api/snapshotsList snapshots
GET/api/snapshots/historySnapshot history
GET/api/snapshots/{hash}Get specific snapshot
DELETE/api/snapshots/{hash}Delete snapshot
POST/api/snapshots/{hash}/restoreRestore from snapshot

Protocol Analyzer (9)

MethodEndpointDescription
GET/api/analyzerCapture status
POST/api/analyzer/startStart capture
POST/api/analyzer/stopStop capture
GET/api/analyzer/transactionsList captured packets
DELETE/api/analyzer/transactionsClear buffer
GET/api/analyzer/statsCapture statistics
POST/api/analyzer/decodeDecode hex packet
GET/api/analyzer/export/pcapDownload PCAP
GET/api/analyzer/protocolsSupported protocols

Store-and-Forward (10)

MethodEndpointDescription
GET/api/storeforward/countQueue count
POST/api/storeforward/storeStore message
POST/api/storeforward/forwardForward pending
GET/api/storeforward/pendingView pending
DELETE/api/storeforward/clearClear queue
GET/api/storeforward/statsQueue statistics
POST/api/storeforward/initInitialize subsystem
POST/api/storeforward/closeShutdown subsystem
POST/api/storeforward/onlineSet network state
POST/api/storeforward/forward-httpForward via HTTP

Other Groups

GroupCountDescription
/api/docs/*2Function docs and guides
/api/config/*4Runtime config read/write
/api/nodered/*4Node-RED management (start/stop/restart/status)
/api/license/*5License activation and status
/api/libraries/*5ST library management
/api/io/*5I/O mapping configuration
/api/drivers/*7Protocol driver management
/api/serial/*6Serial port discovery and management
/api/wizard/*5Configuration wizard
/api/project/*7Project file management
/api/files/*2File upload/download
/api/tags/*3Tag browsing
/api/watch/*2Variable watch lists
/api/l5x/*3Rockwell L5X import/export
/api/logs/*2Log ring buffer access
/api/datalayer/*2DataLayer status
/api/dl-bridge/*2ctrlX Data Layer bridge
/api/pubsub1PubSub configuration
/api/agent/deploy1AI agent deploy
/api/devices/import-map1Device map import
/api/auth/*1Authentication status
/api/fuxa/*1FUXA SCADA proxy

3. Authentication

Authentication is optional. When enabled, all API requests require a Bearer token.

Get Token

curl -X POST http://localhost:8082/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username": "goplc", "password": "goplc"}'

Response:

{"token": "eyJhbGciOiJIUzI1NiIs..."}

Use Token

curl http://localhost:8082/api/variables \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."

Configuration

api:
auth:
enabled: true
jwt_secret: "" # Auto-generated if empty
token_expiry_hours: 24
users:
- username: goplc
password_hash: "$2a$10$..." # bcrypt hash

When auth is disabled (default), all endpoints are accessible without a token.


4. WebSocket — Real-Time Variables

Connect to ws://host:port/ws for real-time variable push updates.

Connection

const ws = new WebSocket('ws://localhost:8082/ws');

ws.onopen = () => {
// Subscribe to specific variables
ws.send(JSON.stringify({
subscribe: ['temperature', 'pressure', 'motor_running']
}));
};

Server Messages

Connected:

{
"type": "connected",
"client_id": "ws-001",
"message": "Send {\"subscribe\": [\"var1\"]} to subscribe"
}

Subscribed confirmation:

{"type": "subscribed", "tags": ["temperature", "pressure"], "timestamp": "..."}

Variable updates (every 100ms default):

{
"type": "update",
"data": {
"temperature": 72.5,
"pressure": 45.3,
"motor_running": true
},
"timestamp": "2026-04-05T10:30:00Z"
}

Client Commands

CommandExampleDescription
Subscribe{"subscribe": ["var1", "var2"]}Add variable subscriptions
Unsubscribe{"unsubscribe": ["var1"]}Remove subscriptions

Broadcast interval is configurable via api.broadcast_interval in config (default: 100ms).


5. Common Patterns

Read and Write Variables

# Read all variables
curl http://localhost:8082/api/variables

# Read single variable
curl http://localhost:8082/api/variables/temperature

# Write a variable
curl -X PUT http://localhost:8082/api/variables/setpoint \
-H "Content-Type: application/json" \
-d '{"value": 75.0}'

# Bulk read
curl -X POST http://localhost:8082/api/variables/bulk \
-H "Content-Type: application/json" \
-d '{"names": ["temperature", "pressure", "flow"]}'

Deploy a Program

# Upload ST code
curl -X POST http://localhost:8082/api/programs \
-H "Content-Type: application/json" \
-d '{
"name": "POU_Control",
"source": "PROGRAM POU_Control\nVAR\n counter : INT := 0;\nEND_VAR\n counter := counter + 1;\nEND_PROGRAM"
}'

# Reload and start
curl -X POST http://localhost:8082/api/programs/reload
curl -X POST http://localhost:8082/api/runtime/start

Download / Upload Project

# Download current project
curl http://localhost:8082/api/runtime/download -o project.goplc

# Upload project
curl -X POST http://localhost:8082/api/runtime/upload \
-F "file=@project.goplc"

Check Health

# Simple health check (returns 200 if running)
curl http://localhost:8082/api/status

# Full diagnostics
curl http://localhost:8082/api/diagnostics

6. Response Formats

Success

{"status": "ok", "message": "Program created"}

Error

{"error": "Program not found: POU_Missing"}

Variable

{
"name": "temperature",
"type": "REAL",
"value": 72.5,
"scope": "global"
}

Task

{
"name": "MainTask",
"state": "running",
"priority": 1,
"scan_time_ms": 50,
"scan_count": 123456,
"last_scan_us": 45,
"avg_scan_us": 42,
"max_scan_us": 312,
"faulted": false,
"watchdog_trips": 0
}

Runtime Info

{
"version": "1.0.1064",
"hostname": "goplc-plant1",
"os": "linux",
"arch": "amd64",
"uptime_seconds": 86400,
"state": "Running"
}

Appendix A: Endpoint Count by Group

The per-group counts below are an approximate snapshot. The authoritative, always-current count comes from the live OpenAPI 3.1 spec at /api/openapi.json — currently 407 operations across 336 paths (52 subsystem tags).

GroupCount
Debug41
Fleet16
Store-Forward10
Runtime10
Programs10
Cluster Ops10
Tasks9
Cluster9
Analyzer9
System8
Project7
Drivers7
Serial6
HMI6
Wizard5
Variables5
License5
Libraries5
I/O5
AI5
Snapshots5
Config4
Node-RED4
Tags3
L5X3
All others21
Total407 operations / 336 paths

ControlForge v1.0.1064 | 407 Operations / 336 Paths | OpenAPI 3.1 (/api/spec-ui) | WebSocket Real-Time

© 2026 JMB Technical Services LLC. All rights reserved. Back to All Guides