/v1 (or /api/v1) path segment — routers mount directly at their resource path, so a request URL is just the base URL joined to the route (for example https://api.modulex.dev/workflows). This page covers the base URL, how to point each surface at a different environment, the trailing-slash rule, and how the API and the SDKs are versioned.
For how to authenticate those requests, see Authentication. For the request lifecycle and content types, see the API overview.
Base URL
Both the JavaScript SDK and the Python SDK default to
https://api.modulex.dev, so you do not set the base URL for normal use. You only override it to target a local backend or a self-hosted deployment.
The production OAuth redirect target — where a browser is sent back after connecting a credential — is the ModuleX app at
https://app.modulex.dev, not the API host. The API host https://api.modulex.dev only serves REST endpoints and the realtime streams. See Credentials & OAuth2.How a request URL is built
The SDKs build every request URL asbaseUrl + path, with no version segment inserted. 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
No /v1 path segment
ModuleX does not put a version number in the URL path. Every resource router mounts directly at its prefix:
Trailing slashes
The API has automatic trailing-slash redirects 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.
Switching environments
You change the environment by changing the base URL. Authentication is unchanged across environments — every request still sendsAuthorization: Bearer mx_live_… and, for organization-scoped endpoints, X-Organization-ID. Use a key that belongs to the environment you are calling.
Configuring the base URL per SDK
The two SDKs differ in whether the base URL can come from an environment variable. This matters when you deploy the same code to different environments.string
default:"https://api.modulex.dev"
Python SDK. Set it explicitly on the constructor, or set the
MODULEX_BASE_URL environment variable, or let it fall back to the default. The resolution order is constructor argument → MODULEX_BASE_URL → default. The same fallback exists for MODULEX_API_KEY and MODULEX_ORGANIZATION_ID.string
default:"https://api.modulex.dev"
JavaScript SDK. Set it on the constructor (
baseUrl) or omit it for the default. The JavaScript SDK has no environment-variable fallback — there is no MODULEX_BASE_URL lookup, and likewise no env fallback for the API key or organization ID. Read any environment variables in your own code and pass the value to the constructor.JavaScript — env-driven base URL (you read the env var)
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 no API-version request header to send. The backend application advertises an internal version string of 0.1.2 (visible at the service root GET / and the health endpoint GET /system/health), but you do not pass a version on a request, and you cannot pin to a specific API version from the client side.
Because there is no version negotiation, ModuleX evolves the API in a backward-compatible way wherever possible. Track changes that affect you through the changelog, and use the SDK ⇄ API parity matrix to confirm which routes a given SDK release covers.
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 type rather than event, and the removal of client-side billing helpers from the JavaScript SDK.
The Python SDK sends a
User-Agent of modulex-python/<version> on every request; the JavaScript SDK does not set a User-Agent. Neither identifies an API version, because the API is unversioned.Interactive API documentation
The running backend also serves machine- and human-readable API references at the base URL:
For the curated, language-tabbed reference and a live “Try it” playground inside these docs, use the API overview and the endpoint reference. To check live availability, see System status & health.
What does not change per environment
Switching environments changes only the base URL. The following are the same 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. See Authentication.2
Route paths
The same paths with no
/v1 segment, called without a trailing slash.3
Error envelopes
The same three error shapes, including the billing
DenialEnvelope returned as 402 / 403 / 429 on metered 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
Make your first API call
Authenticate and run a workflow with cURL, Python, and JavaScript.
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.
SDK ⇄ API parity matrix
Which REST routes each SDK release maps to, with gaps called out.