Roux V4 Developer API

Build against the governed hosted surface: authenticated REST reads, a capability-gated operation channel, streamed import, a bearer-mode JavaScript client, signed webhooks, and first-party custom visuals.

Profile-aware contract. Route availability and credential handling depend on the selected authentication provider, workspace mode, runtime profile, and caller capability. This page documents the current V4 implementation, not an irrevocable compatibility promise.

Authentication

Roux supports three implemented ordinary-authentication profiles. OIDC is a reserved provider name but is not currently an implemented direct provider.

ProviderCredentialContract
NativeOpaque server-side session in a Secure, HttpOnly, SameSite=Lax cookieEvery authenticated native-session POST /call and upload request requires the session-bound CSRF value in x-roux-csrf, including read operations sent through /call; the public health operation is the exception. Login, logout, activation, and password lifecycle stay server-managed.
External bearerAuthorization: Bearer <jwt> or the compatibility header x-roux-session: <jwt>The configured IdP issues ordinary user tokens. Roux always verifies signature, allowed algorithm, and expiry; issuer and audience are verified when configured and are mandatory in the public-key/JWKS and multi-tenant topologies that require them. When its user directory is enabled, Roux also verifies admission and current authorization-store status.
Development bearerLocally issued development tokenLoopback-only and refused when network-exposed. Never use it as a production login.
Do not self-assert embed access. An ordinary IdP token containing embed:true is refused.

Route inventory

Operations and readiness

GET /healthz
Canonical external unauthenticated process liveness.
GET /readyz
Canonical external deployment readiness. In the shipped Hostinger edge profile, /readyz/core is an internal subrequest only and the backend aliases /health, /livez, and /ready return 404 externally.

Native authentication

GET /auth/config · GET /auth/session
Public auth capabilities and the server-authoritative current-session projection.
POST /auth/login · /auth/logout · /auth/activate · /auth/change-password
Native credential and session lifecycle. These routes exist only in native mode.
POST /login
Loopback-only development bearer issuer. It exists only when ROUX_DEV_LOGIN is enabled with a symmetric secret and no real IdP/public key/JWKS; otherwise the route is absent. It accepts a development subject, optional topology-valid organization, bounded memberships, and attributes, then returns an ordinary token only after the same admission path accepts it. It never mints embed credentials.

Data and operations

GET /api/v1/state · GET /api/v1/rows/{id}
Governed read surfaces described below.
POST /call
Capability-, transport-, role-, workspace-, and policy-gated engine operations.
POST /api/v1/upload
Authorized streamed CSV, TSV, or Parquet import in workspace mode.

Governed REST reads

Success uses { ok:true, data }. Authentication, workspace resolution, authorization, row policy, and column policy are applied server-side where relevant. Workspace owners retain full-row access.

Workspace selection: x-roux-workspace takes precedence over ?ws=, and neither value is proof of access. In ordinary workspace mode, a missing, unknown, or non-member selector resolves to the caller's isolated personal workspace; constrained profiles may impose a fixed target. Clients should verify the returned session/workspace projection before a consequential action.
RouteResult and availability
GET /api/v1/state?ws=<workspace>Returns data.state, the authorized workspace specification, when workspace-mode transport exposes getState.
GET /api/v1/rows/<id>?ws=<workspace>Returns data.rows and data.version for an authorized in-memory dataset slice.
Large/columnar data: DuckDB-backed datasets deliberately return no materialized full row array through getRows. Use op:"page" for bounded row windows (up to the server limit) and op:"query" for server-side aggregation.
curl -s https://your-roux-host/api/v1/state?ws=sales \
  -H "Authorization: Bearer $TOKEN"

Operation channel

POST /call accepts { op, args }. health is the only unauthenticated operation; every other network operation requires the configured credential. Every authenticated native-session call also requires x-roux-csrf, even when the selected operation is read-only. A successful operation returns HTTP 200 with { ok:true, value }. A typed engine failure preserves { ok:false, error } and uses its typed HTTP status. Desktop-only, secret, unknown, or unauthorized operations are refused before execution.

curl -s https://your-roux-host/call \
  -H "Authorization: Bearer $TOKEN" \
  -H "x-roux-workspace: sales" \
  -H "content-type: application/json" \
  -d '{"op":"query","args":{"entityId":"d1","dims":["region"],"metrics":[{"name":"total","expr":"SUM([v])"}]}}'

Errors can include message, code, status, reason, retryable, storage-state, conflict, or current-version markers. Clients must handle at least 400, 401, 403, 404, 405, 408, 409, 413, 415, 422, 429, 500, and 503 and must not fall back to ungoverned data.

Streamed import

POST /api/v1/upload is a governed write route available only when workspace-mode upload authorization is wired. The optional x-roux-filename supplies the safe display name and format extension; omission defaults to upload.csv. The body is the CSV, TSV, or Parquet bytes. Roux authenticates and authorizes before reading body bytes, applies declared and measured size limits, streams with backpressure to a private temporary file, and then hands the server-owned path to DuckDB ingestion.

Operators configure byte ceiling, temp directory, free-space reserve, per-user/global concurrency, and body-idle timeout. The constrained public-demo profile denies this route.

JavaScript API client

/roux-sdk.js is a framework-free bearer-mode client. It provides getState, getRows, query, and low-level call, and throws a real RouxError for non-success responses or error envelopes.

Native-mode boundary: this SDK sends a bearer header. It does not implement native login, cookie-session, or CSRF lifecycle. Use the first-party hosted transport or an explicitly designed native-session client for native deployments.
<script src="https://your-roux-host/roux-sdk.js"></script>
<script>
  const roux = RouxAPI.client({
    base: "https://your-roux-host",
    token: TOKEN,
    workspace: "sales"
  });
  const state = await roux.getState();
  const result = await roux.query({
    entityId: "d1",
    dims: ["region"],
    metrics: [{ name: "total", expr: "SUM([v])" }]
  });
</script>

Embedding and publication links

Outside the organization needs an administrator's permission. Owners and editors publish dashboards to their own organization. A link anyone can hold, a named person in another organization, and an embed credential all reach outside it, so each needs an administrator to allow it for that user; without that permission the server refuses with EXTERNAL_PUBLISH_NOT_PERMITTED. A server whose operator turned publishing off answers 503.

Signed webhooks

Operator-configured subscriptions can receive a best-effort dataset.changed event after a successful operation classified as a governed write. The payload identifies what changed but contains no row data. Roux adds event, stable delivery-id, and timestamped HMAC-signature headers.

Delivery is fire-and-forget. There is no Roux-side durable queue or automatic retry. Verify the timestamp and HMAC against the raw body, reject replays, and use the delivery id as an idempotency key.

First-party custom visuals

defineVisual() in src/visuals/registry.js registers a visual kind with defaults and a React render function; namespaced identifiers are a recommended convention, not a runtime-enforced rule. Registered visuals use the ordinary canvas geometry, selection, resize, rotation, and inspection seams. Custom visual code runs with first-party application trust; do not load untrusted author code without a separate sandbox.

Operator configuration

ROUX_AUTH_PROVIDER selects the profile. External bearer deployments configure an allowed algorithm, verification key/JWKS, origins, and allowed hosts; issuer and audience are topology-dependent, with startup enforcing them where required. Native mode requires the user store, invite-only identity, and either in-process HTTPS or an explicitly trusted TLS proxy; its ordinary sessions do not require a JWT verifier. Any provider profile that will mint Roux-derived embed or publication credentials also needs the symmetric Roux session secret.

Webhook subscriptions and private-target policy, frame-ancestor origins, rate limits, upload storage/limits, audit paths, DuckDB limits, and readiness contracts are operator-owned configuration. The server refuses dangerous or internally inconsistent values rather than guessing.