Skip to main content
Version: 0.1

Administration

The routes an administrator uses to run the gateway. Most live under /api/v1/admin and need the admin role; modes, app settings and preferences are elsewhere and are noted per route. Database connections and storage are on Connections; event streams, alarm pipelines and clients on Other routes.

Users​

Method and pathRolePurpose
GET /api/v1/admin/setupanonymous{"needsSetup": true} while the gateway has no user
GET /api/v1/admin/usersadminEvery user, oldest first
POST /api/v1/admin/usersadmin, or anonymous for the first userCreate a user
PATCH /api/v1/admin/users/{id}adminChange a user's role
DELETE /api/v1/admin/users/{id}adminDelete a user

A user is { "id", "name", "email", "emailVerified", "role", "createdAt" } (createdAt ISO-8601).

POST /api/v1/admin/users body: email (required), name, password (required), role (default viewer; one of viewer, operator, engineer, admin, else 400). Without a session it works only while the gateway has no user at all, and then creates the admin whatever role the body asks for; otherwise it answers 401 {"message":"Authentication required to create users"}. With a session it needs admin (403). A duplicate email is 409.

PATCH /api/v1/admin/users/{id} body {"role": "engineer"} (role required). Demoting or deleting the last admin answers 409 {"statusCode":409,"message":"A gateway must keep at least one admin."}; the check is part of the write, so two admins demoting each other at once cannot both succeed. DELETE answers 204.

More in Users and roles.

API keys​

Method and pathRolePurpose
GET /api/v1/admin/api-keysadminEvery key, newest first; never the secret
POST /api/v1/admin/api-keysadmin (session only)Create a key; the secret is in this response and nowhere else
DELETE /api/v1/admin/api-keys/{id}adminRevoke; the row stays

POST body: name (required, up to 80 characters), role (viewer, operator or engineer; 400 otherwise), expiresInDays (optional, 1 to 3650). It must be called by a signed-in person, not another key (400). Response:

{ "id": "…", "name": "Historian export", "prefix": "scx_AbCdEf", "role": "engineer", "createdAt": "…", "expiresAt": null, "secret": "scx_…" }

The list adds lastUsedAt (refreshed at most once a minute) and revokedAt. All ISO-8601. See API keys.

Backup and restore​

Method and pathRolePurpose
GET /api/v1/admin/backupadminDownload a consistent copy of the gateway database
GET /api/v1/admin/restoreadmin{"pending": false, "stagedAt": null}: whether a restore waits for the next start
POST /api/v1/admin/restoreadminStage a backup, sent as the raw request body (up to 512 MB)
DELETE /api/v1/admin/restoreadminDrop a staged restore

The backup is a SQLite file (application/octet-stream, named scadex-backup-<yyyyMMdd-HHmmss>.db) taken with VACUUM INTO while the gateway runs. It holds settings, tags, screens stored in the database, users and history, not licenses, module files or Data Protection keys. The staged file is validated now (400 with the problem when it is not a usable database) and swapped in at the next start; the database it replaces is kept in the backups folder. POST answers 202 {"pending": true}. See Backup and restore.

Identity providers​

Method and pathRolePurpose
GET /api/v1/admin/identity-providersadminEvery provider, by name
POST /api/v1/admin/identity-providersadminAdd an OIDC provider
PUT /api/v1/admin/identity-providers/{id}adminReplace its settings
DELETE /api/v1/admin/identity-providers/{id}adminRemove it and the account links it made; the people stay
POST /api/v1/admin/identity-providers/{id}/testadminRun OIDC discovery against the issuer

ProviderBody:

FieldTypeRequiredMeaning
namestringyesUp to 60 characters
issuerstringyesFull https:// address; plain http only for this machine
clientIdstringyesUp to 300 characters
clientSecretstringnoStored encrypted; blank on an edit keeps the saved one
scopesstringnoDefault openid email profile; openid is added if missing
defaultRolestringnoviewer (default), operator or engineer; never admin
allowedDomainsstring[]noUp to 20 plain domain names; empty means any
linkExistingAccountsbooleannoDefault false
enabledbooleannoDefault true

The response adds hasSecret, redirectUri ({AUTH_BASE_URL}/api/auth/idp/{id}/callback, to register at the provider) and createdAt. The test route answers {"ok": true, "authorizationEndpoint": "…"} or {"ok": false, "error": "…"} with HTTP 200 either way. The login flow is on Authentication; the dashboard side on Identity providers.

Modes​

Named gateway states such as Production or Maintenance. Routes under /api/v1/modes.

Method and pathRolePurpose
GET /api/v1/modesviewerEvery mode, by name
POST /api/v1/modesadminCreate (name up to 40 characters, required; description up to 300). At most 50 modes; names are unique, case-insensitive
PUT /api/v1/modes/{id}adminRename or re-describe
POST /api/v1/modes/{id}/activateadminMake it the one active mode
DELETE /api/v1/modes/{id}adminDelete; the active mode cannot be deleted (400)

A mode is { "id", "name", "description", "active", "createdAt", "activatedAt" }. See Modes.

App settings​

/api/v1/app-settings is one singleton record.

Method and pathRolePurpose
GET /api/v1/app-settingsviewerThe settings
PATCH /api/v1/app-settingsengineer; admin for projectDirChange them

Body fields: openStartOnLaunch (boolean), projectDir (string; the directory where screens are read and written; "" clears it; a directory that cannot be opened is 400; sending it needs admin, 403 otherwise), startScreenId (accepted but read-only history: start screens live under /api/v1/start-screens). The response is the stored entity. See Settings.

Preferences​

/api/v1/preferences holds the signed-in person's own dashboard settings. Every role may change its own; the routes need a session cookie, not an API key.

Method and pathRolePurpose
GET /api/v1/preferencesviewer (session)The caller's preferences
PATCH /api/v1/preferencesviewer (session)Change them

Fields and allowed values: mode (light, dark, system), lightTheme, darkTheme (free text), accent (default, teal, blue, violet, rose, amber, emerald, pink, cyan, orange, indigo), density (compact, normal, comfortable), radius (none, sm, default, lg, xl), cornerShape (squircle, round), font (system, serif, mono), sidebarSide (left, right), sidebarVariantOpen and sidebarVariantCollapsed (sidebar, floating, inset), sidebarCollapsible (offcanvas, icon, none), watchlist (array of tag paths, up to 24, each up to 512 characters; more is 400). A value outside its list is ignored. The response is the full preference object with id, userId and updatedAt.

Who am I​

Method and pathRolePurpose
GET /api/v1/healthanonymous{"status": "ok", "time": "<ISO-8601>"}
GET /api/v1/meviewer (session){ "session": { "session": {...}, "user": {...} } }, the same session and user shapes as GET /api/auth/get-session

Diagnostics and gateway logs​

Method and pathRolePurpose
GET /api/v1/admin/diagnosticsadminmemoryBytes, managedHeapBytes, cpuSeconds, threadCount, busyPoolThreads, processorCount, runtime, os
GET /api/v1/admin/logs?level=&search=&before=&limit=200adminThe newest gateway log lines kept in memory, newest first. level defaults to information; limit 1 to 1000; before is the previous page's last id

Module logs are per module; see Runtime and modules. Dashboard side: Logs and diagnostics.

Script console​

POST /api/v1/admin/script-console (admin) body {"source": "…", "dryRun": true}. Runs a script as the caller with the whole system.* API under screen-script limits. A dry run (default) reads anything but changes nothing: tag writes and changing calls are reported in wouldWrite and skipped. Without it, writes are applied in order, stopping at the first refused. Response: { "ok", "undefined", "value", "error", "dryRun", "wouldWrite": [{path, value}], "written": [{path, value, accepted, error}], "skipped", "logs": [{level, message}], "millis" }. See Script console.

Write audit log​

GET /api/v1/admin/audit/tag-writes?tag=&principalId=&before=&limit=100

Admin. Every attempt to change a tag value, newest first; limit 1 to 1000; pass the last id of a page as before. Rows:

{ "id": 4410, "at": "2026-11-08T12:00:00+00:00", "principalId": "…", "principalName": "…", "principalEmail": "…", "operation": "write", "tagId": "…", "tagPath": "…", "moduleId": "io.scadex.opcua", "value": "42", "correlationId": null, "outcome": "accepted", "error": null, "completedAt": "…" }

operation is write or publish; outcome is accepted, rejected, failed or pending. The response header X-Scadex-Audit-Store names where the log was read from (the gateway database or an outside database under Storage), and X-Scadex-Audit-Warning says when reading it failed. See Audit log.