Getting Started

The ecbyts Automation API provides programmatic access to the Environmental Digital Twin application. It enables external tools, scripts, and AI agents to control the application running in the browser via REST endpoints and WebSocket commands.

Quick Start

# Start the API server
npm run api

# Check server health
curl http://localhost:4000/api/health

# List all available actions
curl http://localhost:4000/api/actions

# Generate a random model
curl -X POST http://localhost:4000/api/action \
  -H "Content-Type: application/json" \
  -d '{"action":"generateRandomModel"}'

Security

Scope note - monetization endpoints such as API key validation, telemetry, metering, library checkout, marketplace, and payment webhooks are documented separately in ecbytsadmin monetization docs.

Health & Status

GET /api/health Server status & browser connection

Response

{
  "success": true,
  "data": {
    "browserConnected": true,
    "uptime": 142,
    "actionsCount": 196,
    "pendingRequests": 0
  }
}
GET /api/state Full model state (elements, campaigns, scenes)

Returns the complete model state as built by buildModel(). Equivalent to exporting the model as JSON.

GET /api/ui/state UI state (selected element, language, active tab)

Response

{
  "selectedElement": "el_abc123",
  "elementCount": 12,
  "campaignCount": 3,
  "sceneCount": 2,
  "language": "en",
  "activeRibbonTab": "modeling"
}
GET /api/ui/consistency Visual consistency audit (icons, fonts, theme)

Runs a visual audit of the UI. Checks icon hydration, font families, open modals, button styling, theme variables, and form input classes.

Elements

GET /api/elements List all elements

Returns all elements with their data (excluding Three.js mesh references). Each element has: id, family, name, visible, label, color, data, stamps.

GET /api/elements/:id Get single element by ID

Parameters

ParamTypeDescription
:idstringElement ID
POST /api/elements Create new element

Request Body

{ "familyId": "well" }

Valid family IDs: plume, well, lake, river, spring, building, tank, waste, boundary, sensor, or any custom family.

PATCH /api/elements/:id Update element properties

Request Body

{
  "updates": {
    "name": "MW-01",
    "coordinates": { "easting": 350000, "northing": 7400000 }
  }
}
DELETE /api/elements/:id Remove element

Removes the element and all associated observations, stamps, and edges.

GET /api/elements/:id/observations Get element observations

Returns the observations[] array from the element's data.

GET /api/elements/:id/stamps Get element stamps

Returns governance, context, and reporting stamps attached to the element.

GET /api/elements/:id/edges Get element edges (relationships)

Returns all edges (incoming + outgoing) connected to the element.

Campaigns

GET /api/campaigns List all sampling campaigns

Returns all campaigns with their date, team, and visibility state.

POST /api/campaigns Create new campaign

Creates a new sampling campaign with default values. No request body required.

PATCH /api/campaigns/:id Update campaign field

Request Body

{
  "field": "name",
  "value": "Q1 2026 Sampling"
}
DELETE /api/campaigns/:id Remove campaign

Removes the campaign. Observations linked to this campaign are NOT removed.

Scenes

GET /api/scenes List all saved camera views

Returns all saved scene (camera view) snapshots.

POST /api/scenes Create new scene

Creates a new scene with default camera position.

DELETE /api/scenes/:id Remove scene

Removes the saved camera view.

Families

GET /api/families List all element families

Returns built-in and custom families with id, name, icon, code, enabled state.

POST /api/families Create custom family

Request Body

{ "id": "piezometer", "name": "Piezometer", "icon": "gauge" }
DELETE /api/families/:id Remove custom family

Removes a custom family. Built-in families cannot be deleted.

Edges

GET /api/edges List all element relationships

Returns all edges with source, target, type, and metadata.

GET /api/edges/:id Get single edge by ID

Parameters

ParamTypeDescription
:idstringEdge ID

Stamps

GET /api/stamps All stamps across all elements

Returns stamps grouped by element. Each entry includes elementId, elementName, family, and stamps[].

Groups

GET /api/groups All element and family groups

Returns the full groups state: elementGroups[], familyGroups[], elementGroupMap, familyGroupMap.

GET /api/groups/:id Get single group by ID

Returns a single group object with id, name, color, collapsed, order.

Auth

GET /api/auth/status Current authentication status

Response

{
  "user": { "email": "user@example.com", "provider": "google" },
  "loggedIn": true,
  "email": "user@example.com",
  "role": "admin",
  "observerMode": "disabled",
  "accessControlActive": true,
  "owner": "admin@example.com"
}
GET /api/auth/rules Access control rules list

Returns the array of access rules. Each rule has: email, role (owner/admin/editor/viewer/observer), areas[].

GET /api/auth/permissions Full permissions config

Returns the complete access configuration: owner, observerMode, rules[].

Ticker

GET /api/ticker Ticker configuration and items

Returns the full ticker config: visible, speed, separator, items[]. Each item has filters[], calculation, label, unitId, precision, color.

GET /api/ticker/values Current computed ticker values

Returns the live computed values for all enabled ticker items. Each entry has: id, text, color.

SAO Protocol

GET /api/sao SAO protocol status

Response

{
  "active": true,
  "scenario": "tailings_dam",
  "tier": "recommended",
  "matrices": ["agua", "solo", "ar"],
  "parameterCounts": { "agua": { "essential": 15, "recommended": 28, "total": 45 } }
}
GET /api/sao/parameters Active monitoring parameters

Returns all currently active parameters based on the selected scenario, tier, and matrices. When SAO is inactive, returns all CONFIG.PARAMETERS.

Governance

GET /api/governance Contracts, WBS, and EVA data

Returns the governance section of the model: contracts, WBS items, parties, disbursements, and EVA calculations. Returns null if no governance data exists.

Sensors

GET /api/sensors/:elementId Fetch live sensor data

Fetches live data for a sensor-family element via its 3-stage pipeline (JSONPlaceholder, FakerAPI, OpenWeatherMap). Element must be of family sensor.

Timeout: 30 seconds (async operation)

Agents

GET /api/agents List all LLM agents

Returns all agents (6 system + user-created). Each agent has: id, name, description, systemPromptAddition, system (boolean).

GET /api/agents/active Get active agent ID

Response

{ "id": "default" }
GET /api/agents/:id Get single agent by ID

Returns the agent object. System agents: default, regulatory-br, regulatory-us, regulatory-intl, campaign, hse.

Modals

GET /api/modals List open modals

Returns visible modal overlays with their ID, title, and structure info.

GET /api/modals/:id Inspect modal DOM structure

Returns detailed structure: header, body, footer presence, button audit, dimensions.

POST /api/modals/close-all Close all open modals

Closes all visible modals including SAO, stamp, and edge modals.

Panels

GET /api/panels Get panel states (left, right, analytics)

Returns panel visibility, docking state, and dimensions for left, right, and analytics panels.

Chat

GET /api/chat/messages Get LLM chat messages

Query Parameters

ParamDefaultDescription
lastallReturn only the last N messages

Returns the conversation history from the AI assistant chat panel.

Notifications

GET /api/toasts Get visible toast notifications

Returns all currently visible toast notifications with their text, type (success, error, warning, info), and timestamp.

Tabs

POST /api/tabs Switch active ribbon tab

Request Body

{ "tabId": "analysis" }

Switches the active ribbon tab. Common tab IDs: modeling, analysis, tools, view.

Export / Import

GET /api/export/json Export model as JSON

Returns the full model state as a JSON object.

GET /api/export/key Export model as ECO key

Returns the model encoded as an ECBT key string. Timeout: 30 seconds.

POST /api/import/json Import model from JSON

Request Body

{ "model": { /* full model object */ } }
POST /api/import/key Import model from ECO key

Request Body

{ "key": "ECBT.A0000001..." }

Screenshot

GET /api/screenshot Capture screenshot as PNG

Query Parameters

ParamDefaultDescription
modefullfull = entire page, 3d = canvas only

Returns PNG image binary (Content-Type: image/png).

DOM & Eval

GET /api/dom Query DOM elements

Query Parameters

ParamRequiredDescription
selectorYesCSS selector (e.g. .panel, #app)
propsNoComma-separated: style, box, html, classes

Example

curl "localhost:4000/api/dom?selector=%23app&props=style,box"

Requires a local control session cookie plus X-ECBYTS-Control-Token. Bootstrap by opening http://localhost:4000/ and then calling GET /api/local-control/token.

POST /api/eval Evaluate JS expression in browser

Request Body

{
  "expr": "document.title",
  "timeout": 5000
}

Evaluates a JavaScript expression in the browser context. Default timeout: 30s. Use for testing and automation — wrap async imports in (async () => { ... })().

POST /api/reload Force browser page reload

Sends a reload signal to the connected browser tab. The WebSocket bridge reconnects automatically after reload.

Security note: /api/dom, /api/eval, and /api/reload now require both the local control session cookie and X-ECBYTS-Control-Token.

Pipelines

GET /api/pipelines List all BPMN pipelines

Returns all registered pipelines with their ID, name, steps, and status.

POST /api/pipelines Create or update pipeline

Request Body

{
  "id": "my-pipeline",
  "name": "Data Quality Check",
  "steps": [...]
}

Saves a pipeline definition. If id matches an existing pipeline, it is updated.

GET /api/pipelines/:id Get pipeline by ID

Parameters

ParamTypeDescription
:idstringPipeline ID
DELETE /api/pipelines/:id Remove pipeline

Parameters

ParamTypeDescription
:idstringPipeline ID
POST /api/pipelines/:id/run Execute pipeline

Parameters

ParamTypeDescription
:idstringPipeline ID

Executes the pipeline steps sequentially. Rate limited: returns 409 Conflict if the pipeline is already running. Timeout: 30s.

EcoTools

GET /api/ecotool-records Get EcoTool output records

Query Parameters

ParamRequiredDescription
idYesEcoTool identifier

Response

{
  "success": true,
  "data": {
    "id": "tool-123",
    "name": "Soil Analysis",
    "records": [...]
  }
}

Aerial Recognition

GET /api/aerial/diagnostic Run aerial diagnostic analysis

Query Parameters

ParamDefaultDescription
ai0Set to 1 to include AI-powered analysis
resolution512Image resolution for processing

Runs diagnostic analysis on the aerial/satellite image. Timeout: 30s.

POST /api/aerial/recognize Run recognition and import elements

Query Parameters

ParamDefaultDescription
methodalgorithmalgorithm, ml, or ai
resolution512Image resolution for processing

Request Body (optional)

{ "calibration": { ... } }

Runs aerial recognition and automatically imports detected features as elements. Timeout: 30s.

GET /api/aerial/auto-calibrate Auto-calibrate detection thresholds

Query Parameters

ParamDefaultDescription
resolution512Image resolution for calibration

Auto-calibrates recognition thresholds from the boundary image. Timeout: 30s.

POST /api/aerial/clean Remove non-boundary elements

Removes all elements that are not of the boundary family. Used to clean up after recognition runs.

GET /api/aerial/debug-segformer Debug SegFormer model output

Returns raw SegFormer model output for debugging purposes. Timeout: 30s.

LLM

GET /api/llm Get LLM provider configuration

Returns the current LLM provider, model, and connection status.

POST /api/llm Configure LLM provider

Request Body

{
  "provider": "openai",
  "apiKey": "sk-...",
  "model": "gpt-4o"
}

All fields are optional. Only provided fields are updated.

POST /api/llm/test Test LLM connection

Tests the LLM connection with the current configuration. Timeout: 30s.

PDF

POST /api/pdfplumber Extract tables from PDF

Request Body

{
  "filePath": "C:/path/to/file.pdf",
  "pages": "1-5"
}

Response

{
  "success": true,
  "data": {
    "tables": [...],
    "meta": { "cache": "miss" }
  }
}

Extracts tables from PDF via Python pdfplumber. Requires Python 3 with pip install pdfplumber. Results cached for 15 minutes. Timeout: 30s.

Security note: /api/llm, /api/llm/test, and /api/pdfplumber now require the same cookie + token pair.

Actions

GET /api/actions List all available actions with metadata

Returns the ACTION_REGISTRY — array of all registered actions with name, params[], and cat (category).

POST /api/action Execute a single action

Request Body

{
  "action": "handleAddObservation",
  "args": ["el_abc123"]
}

Executes any window.* function matching the handler pattern. The args array is spread as function arguments.

POST /api/action/batch Execute multiple actions sequentially

Request Body

{
  "actions": [
    { "action": "handleAddElement", "args": ["well"] },
    { "action": "handleAddElement", "args": ["plume"] }
  ],
  "stopOnError": true
}

WebSocket Protocol

The API uses WebSocket for real-time communication between the Node.js server and the browser tab.

Connection

# Connect from localhost only
ws://localhost:4000/ws

Message Types

TypeDirectionDescription
readyBrowser → ServerBrowser connected, sends list of available actions
commandServer → BrowserExecute command (with requestId)
responseBrowser → ServerCommand result (with matching requestId)
reloadServer → BrowserForce page reload

Timeouts

Actions Reference

All registered actions available via POST /api/action. Loaded live from the server.

Loading actions from server...

Examples

Create a monitoring well and add an observation

# 1. Create a well
curl -X POST http://localhost:4000/api/elements \
  -H "Content-Type: application/json" \
  -d '{"familyId":"well"}'

# 2. Add observation to the well (use element ID from step 1)
curl -X POST http://localhost:4000/api/action \
  -H "Content-Type: application/json" \
  -d '{"action":"handleAddObservation","args":["el_abc123"]}'

# 3. Set the observation parameter to pH
curl -X POST http://localhost:4000/api/action \
  -H "Content-Type: application/json" \
  -d '{"action":"handleObservationParameterChange","args":["el_abc123",0,"ph"]}'

Generate random model and export

# Generate random model with all element types
curl -X POST http://localhost:4000/api/action \
  -H "Content-Type: application/json" \
  -d '{"action":"generateRandomModel"}'

# Export as JSON
curl http://localhost:4000/api/export/json -o model.json

# Export as ECO key
curl http://localhost:4000/api/export/key

Query module states

# Check auth status
curl http://localhost:4000/api/auth/status

# Get groups configuration
curl http://localhost:4000/api/groups

# Get ticker computed values
curl http://localhost:4000/api/ticker/values

# Get SAO protocol status
curl http://localhost:4000/api/sao

# List all LLM agents
curl http://localhost:4000/api/agents

Batch actions

curl -X POST http://localhost:4000/api/action/batch \
  -H "Content-Type: application/json" \
  -d '{
    "actions": [
      {"action": "handleAddElement", "args": ["well"]},
      {"action": "handleAddElement", "args": ["well"]},
      {"action": "handleAddElement", "args": ["plume"]},
      {"action": "handleAddCampaign"}
    ],
    "stopOnError": true
  }'

Error Codes

StatusMeaningCommon Causes
200SuccessRequest completed. Check success field in response.
400Bad RequestMissing required field (e.g. familyId, action)
404Not FoundUnknown endpoint or element/resource ID not found
405Method Not AllowedWrong HTTP method for endpoint (e.g. DELETE on GET-only route)
413Payload Too LargeRequest body exceeds 5 MB limit
500Server ErrorInternal error in server or browser command execution
503Service UnavailableBrowser not connected to WebSocket
504Gateway TimeoutBrowser command did not respond within timeout (10s / 30s)

Error Response Format

{
  "success": false,
  "error": "Browser not connected"
}