Skip to main content

API Reference

Base: backend PORT (default 8090; compose maps 8090:3000). All tenant routes nest under /api/v1/tenants/:tenantID/... (tenant.v1.routes.js, gated by authProvider + audit middleware). Responses spread data top-level: {success, ...data} (expressUtils.sendResponse).

Auth headers

IdentityHeaderNotes
UserAuthorization: Bearer <Firebase ID token>Verified per request; Socket.IO via handshake.auth.token
API keyAuthorization: api_key <raw-key>Prefix + SHA-256 hash check; isDisabled kills instantly
OperatorAuthorization: Bearer <opaque-session>/api/v1/operator* only; 12 h expiry

Every tenant request also requires membership (checkTenantMembership) + Casbin authorize(P.resource.action) on the domain :tenantID.

Error mapping (index.js + error.util.js)

error.codeHTTPWhen
PERMISSION_DENIED403Casbin deny
INVALID_API_KEY, USER_AUTH_TOKEN_EXPIRED, USER_AUTH_TOKEN_NOT_FOUND, INVALID_LOGIN401Bad/expired credential
VALIDATION_ERROR, INVALID_REQUEST400Zod reject / unknown route shape
anything elseerr.statusCode or 500{success:false, error}

Unknown paths: ALL * → 404 {error: INVALID_REQUEST}.

Routes

Top-level (apps/backend/index.js):

MethodPathAuthNotes
GET/healthnone{status:'ok', timestamp}
*/api/v1/authmixedGET /, GET /config/:tenantID, POST /config/:tenantID
*/api/v1/tenantsuser/API keytenant CRUD + everything below
POST/api/v1/operator/auth/login, /logout; GET /meoperatoropaque sessions
*/api/v1/operatoroperator sessionroles, permissions, widget-library admin
POST/api/v1/tenants/:tenantID/ai/chat/streamtenant + ai.executeSSE/streaming agent; DELETE /session resets
GET/api/v1/oauth/google/auth/:tenantID, /:tenantID/google/url, /google/callbackcallback public10-min JWT state
ALL/webhooks/v1/inbound/:tenantID/:pathSuffix, /v1/inbound/:listenerIDnone (suffix is secret)open CORS

Tenant-nested (/api/v1/tenants/:tenantID/..., permission in brackets):

PrefixKey endpoints
/users [user.*]GET /, POST /, `GET
/roles [role.*]`GET
/apikeys [apikey.*]`GET
/datasources [datasource.*]GET /schemas, `GET
/queries [dataquery.*]GET /schemas, `GET
/workflows [workflow.*]GET /schemas, `GET
/widgets [widget.*]GET /schemas, `GET
/app-pages [appPage.*]GET /schemas, `GET
/listeners [listener.*]GET /status/connections, GET /schemas, `GET
/cronjobs [cronJob.*]`GET
/folders [folder.*]GET /?entityType=, POST /, POST /move, `PATCH
/import [bundle.*]POST /preview, POST /execute
/widget-library [widgetLibrary.*]`GET
/audit [audit.list]GET /, GET /export (CSV)
/:tenantID/ai-config`GET
POST /upload-logomulter 10 MB

Entity lists accept ?folderID=<uuid>; creating any asset grants the creator Casbin * on it.

Socket.IO (config/socket.io.js, index.js)

Client emits: workflow_run_join, widget_workflow_connect, widget_send_input, widget_refresh, widget_workflow_disconnect, join_room|leave_room (listener_test:|tenant:|listener:). Server emits: workflow_data_collection_request, workflow_node_update, workflow_status_update, widget_workflow_connected, widget_context_update, widget_workflow_status. Origins restricted to CORS_WHITELIST.

MCP (apps/mcp-server, :5001)

POST|GET /tenants/:tenantID/mcp (Firebase verifyIdToken per request, StreamableHTTPServerTransport), GET /health → {status, tools, timestamp}. Requires JET_ADMIN_BACKEND_URL + FIREBASE_CREDENTIALS. Tool list served from @jet-admin/mcp-server (allTools).

Rate limits

None enforced in code (no express-rate-limit; legacy nginx.conf limit_req zones are not in the active compose nginx). Apply limits at the edge until in-app limiting lands.