Skip to content
Connect > Data APIs

Data API Configuration

Both Data APIs are configured with process-level properties. Put your changes in local.properties (they override the shipped defaults.properties, which you should not edit), then restart the process. These are process/system properties: set them once for the process, not inside a component directory.

Make sure local.properties is actually loaded

local.properties takes effect only if it is included by the property chain (typically root.properties has #INCLUDE local.properties). On some deployments that line is commented out. If your overrides seem ignored, confirm local.properties is included/active for your deployment, then restart.

Enable the REST query endpoint

The REST server itself rides the Web component's HTTP/HTTPS port by default (ami.rest.uses.web.port=web), so the informational endpoints already answer. But the SQL endpoint is switched off by the shipped default:

ami.rest.plugin.classes=*,!QUERY,!ADMIN

*,!QUERY,!ADMIN loads every REST endpoint except QUERY (SQL) and ADMIN (console). To enable SQL over REST, override it in local.properties so QUERY loads. For example:

ami.rest.plugin.classes=*

Exposing SQL over REST is a security decision

/3forge_rest/query runs arbitrary Center SQL as the authenticated user. Enable it deliberately, keep it behind authentication and TLS, and restrict access with an IP allow-list where appropriate. The recommended production posture for exposing SQL vs. steering integrations to a narrower custom endpoint is still being confirmed with the engineering team.

REST properties

Property Default Meaning
ami.rest.uses.web.port web Name of the Web component whose port the REST server rides. false = use a standalone port instead.
ami.rest.http.port / .https.port unset Standalone HTTP / HTTPS port (used only when not riding the Web port).
ami.rest.http.port.bindaddr / .whitelist unset Bind interface and IP allow-list for a standalone port.
ami.rest.https.keystore.file / .password unset TLS keystore for a standalone HTTPS port.
ami.rest.http.connections.max 8 Handler thread-pool size for a standalone REST port, and so the cap on concurrent REST requests there. Used only when not riding the Web port; on the default Web port it has no effect.
ami.rest.plugin.classes *,!QUERY,!ADMIN Which endpoints load. * = all; !NAME excludes one.
ami.rest.auth.plugin.class ${ami.auth.plugin.class} Authenticator used for HTTP Basic.
ami.rest.auth.plugin.cache.duration 10 seconds How long an authentication result is cached.
ami.rest.show.errors true Include error detail in responses.
ami.rest.show.endpoints true List available endpoints at /3forge_rest.

Enable the WebSocket streaming server

The WebSocket server is opt-in: it opens a port only when you set one. Add to local.properties:

ami.websocket.port=3410

Restart the process. With at least one Center running, the log confirms it started:

Started shared AmiWebSocket server on port 3410, components=[center]

components=[...] lists the Center (and Gateway) names you can reach: the URL path selects one, e.g. ws://host:3410/center. If instead you see WebSocket server disabled (no ami.websocket.port configured), the port is not set.

WebSocket authentication

The shipped default is:

ami.websocket.auth.plugin.class=DISABLED

DISABLED accepts every connection without a credential check, as anonymous when it sends no credentials. Any other value names an authentication plugin, the same plugin type ami.auth.plugin.class takes, which checks the username and password from HTTP Basic credentials on the handshake. The handshake carries nothing else the plugin can check: no session cookie, token, or client certificate. Browsers cannot set an Authorization header on the handshake, so a browser client puts the credentials in the URL. The browser first connects without them, and sends them only when the server answers 401 with a WWW-Authenticate: Basic challenge. With DISABLED there is no challenge, so a browser never sends URL credentials. There are 2 workable postures; which one fits depends on what's actually protecting the connection, not on a single blanket recommendation:

  • DISABLED, behind a trusted network or reverse proxy. Fits when the WebSocket port is never reachable from outside a network you already control: a proxy, a VPN boundary, or a deployment where only trusted services can reach ami.websocket.port at all. The proxy (or network boundary) is the actual control; DISABLED just means AmiCore itself adds nothing on top of it. Wrong fit the moment the port is reachable from an untrusted network, since then nothing authenticates the connection at all.
  • Basic credentials in the URL, wss://user:pass@host:3410/center, with an authentication plugin configured. Fits when you need per-user identity rather than a shared network boundary. The plugin can be ACCESS_FILE or the plugin your Web logins use, such as LDAP, so the WebSocket checks the same users. Costs: credentials appear in the URL, which browsers, proxies, and server logs can all persist: use wss:// (never plain ws://) so the URL is at least encrypted in transit, and treat the credential as sensitive as any other password.

Neither is "the" production recommendation; pick by what's actually true of the deployment: is the port reachable only from a trusted boundary, or does the client need per-user identity. To require a client certificate as well, turn on mutual TLS (see Secure wss://); the authentication plugin still sees only the Basic credentials.

Secure wss://

Set a keystore to serve wss:// with a server certificate; browsers then authenticate with Basic credentials and no client certificate:

1
2
3
ami.websocket.port=3410
ami.websocket.ssl.keystore.file=${ami.global.dir}/keys/3forge.jks
ami.websocket.ssl.keystore.password=${ami.keypass}

Startup then logs ... on port 3410 (secure), components=[...]. Browsers must trust the server certificate (import it, or front the port with a reverse proxy holding a CA-signed cert). Client-certificate mutual TLS is an additional opt-in (ami.websocket.ssl.authorized.clients.file) and is rarely appropriate for browsers.

WebSocket properties

Property Default Meaning
ami.websocket.port (unset → disabled) TCP listen port. Setting this starts the server.
ami.websocket.port.bindaddr all interfaces Interface to bind (e.g. 127.0.0.1 for loopback only).
ami.websocket.port.whitelist none Per-connection client allow-list (text: / file: / plugin:).
ami.websocket.auth.plugin.class DISABLED Authenticator for the handshake. DISABLED = accept without a credential check.
ami.websocket.ssl.keystore.file / .password unset → ws:// Keystore → server-side wss://.
ami.websocket.ssl.authorized.clients.file unset Setting it turns on client-certificate mutual TLS.
ami.websocket.connections.max 64 Max concurrent connections.
ami.websocket.conflate.interval.ms 100 How often coalesced row changes are flushed to clients.
ami.websocket.ping.interval.ms 30000 Idle window before a keepalive PING; 0 disables liveness checks.
ami.websocket.idle.probes 2 Unanswered PING windows tolerated before a silent client is dropped.
ami.websocket.max.message.bytes 1048576 (1 MB) Max size of an inbound message split across several frames. A single frame is capped at 1 MB regardless of this setting. Either limit, when exceeded, closes the connection with status 1009 and reason message too large.