Skip to main content
ModuleX runs as two independently deployed services, and each exposes its own health endpoint. The REST backend (everything behind https://api.modulex.dev — workflows, runs, the Assistant, knowledge, billing) answers a public liveness probe at GET /system/health. The separate realtime collaboration server that powers canvas co-editing answers a public probe at GET /health. This page documents both, plus the two API-key-gated diagnostic endpoints, and tells you where to watch live status.

REST backend liveness

GET /system/health — public, unauthenticated. Returns service name and version. Use it for load-balancer and uptime checks against api.modulex.dev.

Realtime server liveness

GET /health on the collaboration server — public, unauthenticated. Returns uptime, active room count, and connection count. See Realtime overview.
The two services are separate. A healthy REST backend does not imply a healthy realtime server, and vice versa. If realtime co-editing is failing while REST calls succeed, probe the realtime server’s /health directly rather than api.modulex.dev.

Which probe to use

Is the API up?

Call GET /system/health on api.modulex.dev. A 200 with status: healthy means the REST backend is serving. No auth required.

Is co-editing up?

Call GET /health on the collaboration server. A 200 with status: healthy means the Socket.io server is serving, and the body also reports current rooms and connections.

Is the OAuth subsystem healthy?

Call GET /system/health/oauth with an X-Health-API-Key. This runs internal integration-catalog and provider checks. Operator-only.

What are live load stats?

Call GET /admin/stats or GET /admin/quick-stats on the realtime server with admin credentials. Operator-only; see Realtime overview.

REST backend liveness — GET /system/health

The primary liveness probe for the ModuleX REST API. It is public, takes no parameters, and returns a static health document. Use it for uptime monitors, container readiness/liveness probes, and load-balancer checks against api.modulex.dev.
none
This endpoint takes no path parameters, no query parameters, no request body, and no authentication headers. It is mounted at /system/health on the REST backend with no /v1 segment (ModuleX does not version the REST path).
Do not confuse GET /system/health (this public liveness probe, no auth) with GET /system/health/oauth (the API-key-gated diagnostics endpoint documented below). The path strings overlap but they are served by different routers with different auth.

Request

This is a raw HTTP probe, not an SDK operation. The official JavaScript and Python SDKs do not expose a typed health method, so the examples above use a plain HTTP client. No Authorization or X-Organization-ID header is needed.

Response

A 200 OK with a fixed JSON document. The version field is the backend application version string.
200 OK
string
required
Always the literal healthy when the backend is serving requests. The endpoint returns this static value rather than running deep dependency checks, so treat a 200 as a liveness signal (the process is up and routing), not a guarantee that every downstream dependency is reachable.
string
required
Always the literal ModuleX. Lets a multi-service monitor confirm it probed the right backend.
string
required
The backend application version, for example 0.1.2. This is the same version reported by the API’s own metadata. It is a hardcoded string in the deployed build, so it changes only when a new backend version ships.

Status codes and edge cases

status
Returned whenever the backend process is up and routing. The body is the document above.
status
Not specific to this endpoint. If the backend hits an unhandled exception anywhere, it returns the platform-wide envelope {"detail": "An unexpected internal server error occurred."} with status 500. A health probe that returns 500 (or fails to connect) indicates the backend is unhealthy.
  • No trailing-slash redirect. The backend runs with redirect-on-trailing-slash disabled. Probe exactly /system/health — a request to /system/health/ will not auto-redirect and may 404.
  • No /v1 prefix. ModuleX does not put a version segment in the REST path. The path is literally /system/health. See Base URLs & versioning.
  • Static, not a deep check. This probe does not test the datastore, the in-memory store, or model providers. It confirms the process is alive and serving HTTP. For subsystem-level diagnostics use the OAuth health report.
  • No rate-limit or billing gate. This endpoint is outside the billing gate and is safe to poll from an uptime monitor.

Realtime server liveness — GET /health

The realtime collaboration server is a separate service from the REST backend. It powers Socket.io canvas collaboration — presence, cursors, node locks, and live co-editing. It exposes its own public health probe at GET /health (note: /health, not /system/health — the path differs from the backend).
The exact production hostname of the realtime collaboration server is TBD — it is not standardized in the verified source material, which references hosts that conflict with the api.modulex.dev REST host. This page does not publish a production realtime hostname. Probe /health on your deployment’s configured collaboration-server URL. See Open questions. The path and response shape below are verified; only the host is unresolved.
none
This endpoint takes no path parameters, no query parameters, no request body, and no authentication headers. The realtime server’s only public HTTP routes are /health and the admin diagnostics; every other path returns 404.

Request

The host below is a placeholder — substitute your deployment’s collaboration-server URL.

Response

A 200 OK with a live snapshot of the server’s load. Unlike the backend probe, this body changes on every call.
200 OK
string
required
Always the literal healthy when the realtime server is serving. As with the backend probe, this is a liveness signal — the only status string this endpoint emits is healthy; it has no failure path that returns a different value, so a degraded server shows up as a non-200 response or a failed connection.
number
required
Process uptime in seconds (fractional), for example 3725.41. Sourced from the Node process uptime. A small or reset value indicates the realtime server recently restarted.
number
required
The number of active collaboration rooms currently held in memory. Each room corresponds to a workflow canvas with at least one connected editor. See Presence, locks & versioning.
number
required
The total number of connected Engine.IO clients across the server. This counts all clients on the underlying transport, including any connected to the admin namespace — not only canvas editors. It is therefore a different number from the connections figure reported by GET /admin/quick-stats, which counts only main-namespace user connections.
string
required
An ISO 8601 timestamp marking when the server generated this response, for example 2026-06-20T10:15:30.000Z.

Status codes and edge cases

status
Returned whenever the realtime server is up. There is no other success status and no documented error status for this endpoint — it has only the 200 path.
  • Different path from the backend. The realtime probe is /health. The backend probe is /system/health. They are not interchangeable, and they live on different hosts.
  • connections counts more than editors. It reflects every Engine.IO client on the server, including admin-namespace connections. To count only collaborating users, use the admin stats endpoints below.
  • No auth and no rate limit. Like the backend probe, /health is public and ungated. It is safe to poll from an uptime monitor.
  • Flat error shape elsewhere. The realtime server has no shared error envelope. Its other (non-health) routes return a flat {"error": "..."} object with no code field — but /health itself only ever returns the 200 body above.

Operator-only diagnostics

Beyond the two public liveness probes, ModuleX exposes deeper diagnostics that require operator credentials. These are not for application code — they back internal monitoring — but they are documented here so you know what exists.

OAuth subsystem diagnostics — GET /system/health/oauth

A backend diagnostics endpoint that runs internal consistency checks over the integration catalog and OAuth provider configuration. It is gated by a dedicated health API key, distinct from your mx_live_* key.
string
required
The deployment’s configured health-check key. The value is compared in constant time against the server’s HEALTH_CHECK_API_KEY. This is not an mx_live_* API key and not a JWT — it is a separate operator secret. If the deployment has not configured a key, the endpoint returns 503 for everyone.
The response is a structured health report. overall aggregates the individual checks: any check that fails makes overall unhealthy; any warning makes it warning; otherwise it is healthy.
200 OK
status
The report was produced. Inspect overall and each check’s status rather than relying on the HTTP code alone — a 200 can still carry overall: unhealthy.
status
The X-Health-API-Key was supplied but did not match. Body: {"detail": "Invalid health check API key"}.
status
The deployment has no health-check key configured, so the endpoint is disabled. Body: {"detail": "HEALTH_CHECK_API_KEY not configured on this deployment"}.

Realtime load stats — GET /admin/stats and GET /admin/quick-stats

The realtime collaboration server exposes two admin diagnostics endpoints that report live connection, room, and per-organization load. They are operator-only and require both an admin API key and an allowlisted Clerk token — they are not part of the public API and not intended for application code.
string
required
The realtime server’s admin API key. May alternatively be passed as the api_key query parameter. Must match the server’s configured ADMIN_API_KEY.
string
required
A Bearer <clerk_jwt> token. The token’s verified email must match the server’s single allowlisted operator email, or the request is rejected with 403.
GET /admin/quick-stats returns a lightweight, in-memory snapshot computed without scanning sockets:
200 OK
GET /admin/stats returns a much larger snapshot built by scanning every connected socket (server, connections, rooms, trackers, organizations[], activeRooms[], allConnections[], timestamp). It is more detailed but more expensive to compute.
Quick-stats and full-stats are computed by different mechanisms and can disagree. Quick-stats reads in-memory counters and is approximate; full-stats recomputes from live sockets. Quick-stats also reports connection fields flat (connections, activeConnections, idleConnections) while full-stats nests them under connections as total, active, and idle. Treat quick-stats as an approximate, low-cost reading.
Some fields in the full GET /admin/stats payload are placeholders in the current server build and do not carry real telemetry. Do not present them as accurate:
  • Per-connection connectedAt is stamped at collection time, not at real connect time, and connectionDuration is the literal string N/A.
  • Per-room pendingPatches is always 0, createdAt is stamped at collection time, and lastSavedAt is always null.
These are documented source limitations, not live metrics. For the canonical realtime event reference, see Realtime overview.
status
Stats were collected and returned.
status
Missing or invalid admin API key ({"error": "Invalid or missing API key"}), missing token ({"error": "Authentication token required"}), or invalid token ({"error": "Invalid authentication token"}).
status
The token was valid but its email is not the allowlisted operator ({"error": "Unauthorized user"}).
status
Authenticated, but the path under /admin/ is not /admin/stats or /admin/quick-stats ({"error": "Admin endpoint not found"}).
status
Stats collection threw ({"error": "Failed to collect stats"}).
status
The admin API key is not configured on the server, so admin routes are disabled ({"error": "Admin API not configured"}).

Where to check live status

There is no verified public status page for ModuleX in the current source material. Until one is confirmed, do not point readers to a status-page URL.
Public status page: TBD. No public ModuleX status-page URL (for example a hosted incident/uptime page) is verifiable in the source material. When one is confirmed, this page will link it here. Until then, use the public health probes above for an at-a-glance liveness check.
In the meantime, you can:
  • Probe the public health endpoints. GET /system/health on api.modulex.dev for the REST backend, and GET /health on the realtime server for canvas collaboration. Both are unauthenticated and safe to poll.
  • Watch in-app system notices. ModuleX surfaces operational announcements as system notifications inside the app — maintenance windows, incidents, and changelog entries appear in the notifications feed.
  • Track product changes. Notable changes are recorded in the Changelog.
  • Reach a human. If something looks down, see Getting help for support channels.
For container orchestration, point your liveness probe at GET /system/health for the backend and GET /health for the realtime server. Both return 200 with status: healthy when the service is serving and require no credentials, so neither needs a secret baked into the probe configuration.

Open questions

The exact production hostname for the realtime collaboration server is not standardized in the verified source material — it references hosts that conflict with the api.modulex.dev REST host. This page does not publish a production realtime host; use your deployment’s configured collaboration-server URL for the /health, /admin/stats, and /admin/quick-stats endpoints. The local development default is port 3001.
No public ModuleX status-page URL is verifiable in the source material. This page will link it once confirmed. Until then, use the public health probes and in-app system notices described above.