Skip to main content
The ModuleX REST API is served from a single production base URL, with no version segment in the path. Every router mounts directly at its resource path, so a request URL is the base URL joined to the route — for example https://api.modulex.dev/workflows. This reference covers the base URL and how request URLs are composed, the no-/v1 and trailing-slash rules, and how ModuleX versions and deprecates the API. This page is the API-reference companion to Base URLs, environments & versioning, which walks through pointing each SDK at a local or staging backend and the per-SDK environment-variable behavior. For the request lifecycle and content types, see the API overview; to authenticate requests, see Authentication.

Base URL

The API has one canonical production host. The SDKs default to it, so you do not set the base URL for normal use — you override it only to target a local backend or a self-hosted deployment. Both the JavaScript SDK and the Python SDK hardcode https://api.modulex.dev as the default base URL. The Python SDK additionally reads a MODULEX_BASE_URL environment variable as a fallback; the JavaScript SDK does not — see Switching environments for the full resolution order per SDK.
https://api.modulex.dev serves only REST endpoints and the run-event SSE streams. The ModuleX web app and the OAuth redirect target live at a separate host, https://app.modulex.dev, and realtime canvas collaboration runs over a separate Socket.io server. Do not point SDK calls at the app host. See Realtime overview and Credentials & OAuth2.

How a request URL is built

The SDKs build every request URL as baseUrl + path — the route path is appended verbatim, with no version segment inserted and no other rewriting. A trailing slash on the base URL is stripped before the path is joined, so https://api.modulex.dev/ and https://api.modulex.dev behave identically.
Request URL composition
The same call against each surface — note that only the base URL changes:

No /v1 path segment

ModuleX does not put a version number in the URL path. There is no /v1, no /api/v1, and no /api prefix — each resource router mounts directly at its prefix.
Do not prefix routes with /v1 or /api/v1. There is no such segment — a request to https://api.modulex.dev/v1/workflows does not resolve to the workflows router and will not return the list of workflows. Call https://api.modulex.dev/workflows.

Trailing slashes

Automatic trailing-slash redirects are turned off. A route is matched exactly as declared, so request the path without a trailing slash. Always call the canonical path with no trailing slash. The SDKs already do this for you, so this only matters when you build request URLs by hand (for example, in cURL or a custom HTTP client).

Versioning

ModuleX versions the API and the SDKs separately. Neither uses a version segment in the URL path.

API versioning

The API is unversioned in the URL. There is no /v1 path segment, and there is no API-version request header to send or pin — you cannot request a specific API version from the client side. The backend application advertises an internal version string of 0.1.2, visible at the service root GET / and the public health endpoint GET /system/health. This is the build version of the service, not a contract version you negotiate against — it does not change how you call the API and you do not pass it on requests. Because there is no version negotiation, ModuleX evolves the API in a backward-compatible way wherever possible: new fields are additive, and existing fields keep their meaning. Track changes that affect you through the changelog, and use the SDK ⇄ API parity matrix to confirm which routes a given SDK release covers.
Responses are snake_case JSON (for example run_id, created_at, organization_ids). The JavaScript SDK accepts camelCase request parameters and converts them to snake_case on the wire, but does not convert responses — so JavaScript responses are snake_case too. The Python SDK is snake_case end to end. See the SDK ⇄ API parity matrix for the casing rules per SDK.

SDK versioning (semantic versioning)

The official SDKs follow semantic versioning and ship at version 1.0.0. Pin the SDK version in your dependency manifest so a major release does not change behavior under you. Breaking changes land in a new major version; consult the changelog before upgrading across a major boundary. Notable changes already shipped in the 1.0 line include the retirement of the organization member role (invites accept only admin; see Roles & permissions), realtime SSE frames discriminating on a type key inside the JSON rather than a named event line (see SSE run streaming), and the removal of client-side billing helpers from the JavaScript SDK (the subscriptions resource is Python-SDK-only).

Deprecation

ModuleX does not version the API in the URL, so a removed or replaced capability is communicated through the response status and a pointer to its replacement, plus the changelog. There is no Deprecation or Sunset response header to watch for.

Removed endpoints return 410

When a capability is removed rather than changed, the route returns 410 Gone with a detail message that names the replacement. The live example is the former “LLM mode” of the run endpoint: a single-node chat or knowledge Q&A submitted to POST /workflows/run with only an llm config (no workflow, workflow_id, or system_workflow) has been removed in favor of the agentic Assistant.
410 response — LLM mode removed from /workflows/run
A 410 is the FastAPI HTTPException shape — a string detail. It is not the billing DenialEnvelope, and the SDKs do not map 410 to a dedicated error class; it surfaces as the base ModulexError. For the full set of error shapes and which surface emits each, see Errors & status codes.
Run a chat-style prompt or knowledge Q&A through POST /assistant/chat, not through the run endpoint. Sending only an llm config to POST /workflows/run is a removed path and returns 410. The run endpoint is for executing a saved workflow, an ad-hoc workflow schema, or a system workflow.

Deprecated aliases

Some routes are kept as deprecated aliases for backward compatibility rather than removed. For example, the support-request router is mounted canonically at /requests and also at the deprecated alias /support, so POST /support is equivalent to POST /requests. Prefer the canonical path; aliases may be removed in a future major release and are noted in the changelog.

Interactive API documentation

The running backend serves machine- and human-readable references at the base URL. Use these to inspect the live schema for the environment you are calling. For the curated, language-tabbed reference and a live “Try it” playground inside these docs, browse the endpoint pages under API overview. To check live availability, see System status & health.

What does not change per environment

Switching environments changes only the base URL. Everything else about a request is identical across production and a local or self-hosted backend:
1

Authentication scheme

Every request sends Authorization: Bearer mx_live_…, and organization-scoped requests also send X-Organization-ID. Use a key that belongs to the environment you are calling. See Authentication.
2

Route paths

The same paths with no /v1 segment, called without a trailing slash.
3

Error envelopes

The same shapes, including the billing DenialEnvelope returned as 402 / 403 / 429 on the metered run, composer, assistant, and managed-knowledge surfaces. See Errors & status codes.
4

Rate limiting

The same per-key, per-user, and per-organization limits and 429 responses. See Rate limiting.

Next steps

Base URLs, environments & versioning

The getting-started walkthrough: point each SDK at local or staging, with per-SDK environment-variable behavior.

Authentication

The Authorization: Bearer header and X-Organization-ID org context.

API overview

The request lifecycle, content types, and how each operation is shown three ways.

Errors & status codes

The three error shapes, the billing DenialEnvelope, and the 410 removed-endpoint case.