Skip to main content
A deployment is an immutable snapshot of a workflow taken at the moment you deploy it. Each deployment freezes the workflow’s schema, default input, execution config, name, description, and version so that runs use a stable, reviewed copy rather than whatever happens to be on the canvas right now. The deployment you mark as live is the one the API runs when you trigger the workflow by workflow_id. This page covers the full deployment lifecycle: creating a deployment, how versions are assigned, promoting an older deployment back to live (rollback), and deleting deployments. Every operation is shown for the app, the REST API, and both SDKs, with complete parameter, response, and error references.
Deployments are why a workflow can be edited continuously while production runs stay stable. Editing the canvas changes the workflow’s working schema; it does not change any deployment. Runs that load by workflow_id always use the live deployment’s frozen snapshot until you deploy again or promote a different deployment. For the canvas edit-history side of this story, see versioning & history.

How deployments fit into running a workflow

When you trigger a run by workflow_id — from the builder’s run control, a schedule, a chat trigger, a published MCP tool, or the API — the engine loads the schema from the workflow’s live deployment, not from the live canvas. If a workflow has no live deployment, a run-by-id request fails with 400 and the message Workflow has no active deployment. Deploy the workflow first using POST /workflows/{workflow_id}/deploy. There is one exception: an ad-hoc run (the builder’s “Run” on the current canvas, or an inline workflow schema sent to the API) executes the schema you pass in the request and bypasses deployments entirely. Use ad-hoc runs while iterating; deploy when you want a stable target. See running workflows for the run mechanics and run via API for the request body.

Two different “versions”

Do not confuse the two version counters a workflow carries: This page is about the deployment version. The edit_version is covered under versioning & history and presence, locks & versioning.

Permissions and authentication

Every deployment route requires the caller to be an organization owner or admin. The retired member role cannot deploy, promote, roll back, or delete deployments. See roles & permissions for the role model. All API and SDK calls authenticate the same way as the rest of the API — with a bearer API key plus the organization header, as documented in the API overview and authentication:
  • Authorization: Bearer mx_live_…
  • X-Organization-ID: <your org id>
The base URL is https://api.modulex.dev with no version path segment. Requests for a workflow that does not exist in the caller’s organization return 404 (cross-tenant ids are indistinguishable from missing ids).

Credit impact

Deploying, listing, promoting, and deleting deployments are not metered and do not consume credits. None of the six deployment routes pass through the billing admission gate — only POST /workflows/run is credit-charging. This means you will never see a 402/403/429 DenialEnvelope from a deployment call. The billing gate and its `{code, layer, key, current, limit, reason}` envelope are documented under usage gating & limits and errors & status codes; they apply when you run a deployed workflow, not when you deploy it.

Create a deployment

Deploying snapshots the workflow’s current schema, name, description, default input, and config into a new immutable WorkflowDeployment row, then sets that snapshot as the workflow’s live deployment automatically (auto-live). The next run-by-id uses it immediately.
1

Finish your edits on the canvas

Build and test the workflow until it behaves the way you want. Use ad-hoc runs to validate; nothing you do on the canvas affects existing deployments.
2

Deploy

Deploy from the builder, or call POST /workflows/{workflow_id}/deploy. ModuleX copies the current schema into a new snapshot, assigns the next version, and marks it live.
3

Verify the live version

List the deployments and confirm the is_live flag is on the version you expect. Run the workflow by id to confirm it executes the snapshot.

Request

string
required
Path parameter. The UUID of the workflow to deploy. A non-UUID value returns 400 Invalid workflow_id format. A workflow that is not in your organization returns 404 Workflow not found.
string
Optional. A free-text note describing this deployment (for example, Fixed empty-result branch). Stored on the snapshot and returned by the list and get operations. Omit to leave it null.
string
Optional. URL of a visual snapshot of the workflow graph (the app generates this from the canvas). Stored on the snapshot for display in deployment history. Omit to leave it null.
The request body is optional; sending no body deploys the current schema with a null note and image.

Response

string
UUID of the new deployment snapshot.
string
UUID of the parent workflow.
string
Workflow name captured at deploy time.
string
Semantic version assigned to this snapshot — see version assignment below.
string | null
The note you supplied, or null.
string | null
The image URL you supplied, or null.
string | null
UUID of the user who deployed. null if that user has since been removed.
string
ISO-8601 timestamp of the deployment.
boolean
Always true on the create response — a new deployment becomes live immediately.
Example response

Errors

These are FastAPI `{detail}` error envelopes. Deployment routes never return the billing DenialEnvelope because they are not credit-gated. The full error-shape taxonomy is on errors & status codes.

Version assignment

ModuleX assigns the deployment version automatically — you do not pass it. On deploy, the engine reads the most recent deployment for the workflow (by creation time) and computes the next version by incrementing the major component and zeroing the rest:
  • First ever deployment → 1.0.0
  • Next → 2.0.0
  • Next → 3.0.0, and so on.
If the most recent version string cannot be parsed as major.minor.patch, the next deploy falls back to 1.0.0. Versions are never reused, and minor/patch components are not auto-incremented; every deployment is a major bump. The workflow’s own WorkflowMetadata.version (default "1.0", editable on the canvas) is a separate, descriptive field and does not drive deployment numbering.
Deployments are immutable. There is no edit-deployment operation — you cannot change a snapshot’s schema, note, or version after the fact. To ship a change, edit the canvas and deploy again, which produces a new versioned snapshot.

List deployments

List every deployment for a workflow, newest first. Use this to review version history and find the deployment id to promote or delete. The is_live flag marks which snapshot currently runs.
string
required
Path parameter. UUID of the workflow.
integer
default:"20"
Maximum number of deployments to return. Range 1100.
integer
default:"0"
Number of deployments to skip, for pagination. Minimum 0. See pagination for the offset model used across the API.
array
Deployment summaries, newest first.
integer
Total number of deployments for the workflow (ignores limit/offset).
integer
The limit that was applied.
integer
The offset that was applied.
List rows are summaries and omit workflow_id, description, and the full workflow_schema. Fetch a single deployment to get the complete snapshot, including its schema, default input, and config.
Example response

Errors

Get a single deployment

Fetch one deployment with its complete immutable snapshot — the full workflow_schema, default input, and execution config captured at deploy time. Use this to inspect exactly what a version will run, or to diff two versions client-side.
string
required
Path parameter. UUID of the workflow.
string
required
Path parameter. UUID of the deployment.
string
UUID of the deployment.
string
UUID of the parent workflow.
string
Workflow name at deploy time.
string | null
Workflow description at deploy time.
string
Semantic version of the snapshot.
string | null
The deploy-time note, or null.
string | null
Visual snapshot URL, or null.
string | null
UUID of the deploying user, or null.
string
ISO-8601 deploy timestamp.
boolean
true if this is the live deployment.
object
The frozen WorkflowDefinition (metadata, config, state schema, nodes, edges) the run engine executes. The node and reference model behind this schema is documented under workflow engine & nodes and variables & references.
object
Default input parameters captured at deploy time. A run-by-id request can override these per call.
object
Execution config captured at deploy time (for example recursion_limit). A run-by-id request’s config merges over this.

Errors

Promote a deployment (rollback)

Promoting sets a chosen deployment as the live version. Because deployments are versioned snapshots, “rollback” and “promote” are the same operation — you point live_deployment_id at whichever existing snapshot you want to serve. List deployments, find the version to restore, then activate it. The change takes effect on the next run-by-id; runs already in flight are unaffected.
1

Find the target deployment

List the workflow’s deployments and pick the id of the version you want live (for example, the last known-good 1.0.0).
2

Activate it

Activate that deployment from the deployment-history panel, or call PUT /workflows/{workflow_id}/deployments/{deployment_id}/activate. The previously live deployment is returned so you can audit the change.
3

Confirm

Re-list deployments and confirm the is_live flag moved to your target version, then run by id to verify.
string
required
Path parameter. UUID of the workflow.
string
required
Path parameter. UUID of the deployment to make live.
boolean
true on success.
string
Deployment activated successfully, or Deployment is already live when the target was already live (a no-op).
string
UUID of the now-live deployment.
string | null
UUID of the deployment that was live before this call, or null if none was live. Omitted from the already-live no-op response.
Example response

Errors

Deactivate the live deployment

Clearing the live deployment leaves the workflow with no live version (live_deployment_id becomes null). After this, a run-by-id fails with 400 Workflow has no active deployment… until you deploy again or promote an existing deployment. Use this to take a workflow out of service without deleting its history.
string
required
Path parameter. UUID of the workflow.
boolean
true on success.
string
Live deployment deactivated, or No live deployment was active when there was nothing to deactivate.
string
UUID of the deployment that was deactivated. Present only when a live deployment existed.
After deactivating, run-by-id (schedules, chat triggers, and POST /workflows/run with a workflow_id) will fail with 400 until a deployment is live again. Ad-hoc runs that carry an inline schema are unaffected.

Errors

Delete a deployment

Permanently removes a deployment snapshot. If you delete the live deployment, ModuleX automatically promotes the next-most-recent deployment (by creation time) to live; if none remains, the workflow is left with no live deployment. The response reports both what happened.
string
required
Path parameter. UUID of the workflow.
string
required
Path parameter. UUID of the deployment to delete.
boolean
true on success.
string
Deployment deleted successfully.
string
UUID of the deleted deployment.
boolean
true if the deleted deployment had been the live one.
string | null
When was_live is true: the UUID of the deployment auto-promoted to live, or null if no deployment remained. Absent otherwise.
Example response

Errors

Endpoint reference

All routes are mounted under the /workflows prefix with no API version segment, and all require an org owner/admin. The deployments/live route is intentionally declared before the deployments/{deployment_id} route so the literal live segment is matched first and never captured as a deployment id. Both the JavaScript SDK and the Python SDK implement all six operations under the deployments resource on the client, at full parity with REST — see the SDK ⇄ API parity matrix. The SDKs accept and return snake_case fields converted to each language’s idiom (for example is_liveisLive).

Common workflows

Edit the canvas, run ad-hoc to validate, then deployments.create to snapshot and go live. Existing runs are unaffected until you deploy; the next run-by-id picks up the new version automatically.
deployments.list to find the last known-good version’s id, then deployments.activate on it. Live traffic moves to the older snapshot on the next run-by-id. The previously live id is returned so you can re-promote it later if needed.
deployments.deactivate clears the live pointer. Run-by-id then returns 400 Workflow has no active deployment… until you deploy or promote again. History is preserved.
deployments.delete removes a snapshot permanently. Deleting the live one auto-promotes the next-most-recent deployment (or leaves none); check new_live_deployment_id in the response to see where live landed.

Running workflows

Run a deployed workflow from the builder and watch the live stream.

Run via API

Trigger a deployed workflow by id over REST and the SDKs.

Schedules

Schedules require a live deployment to run.

Versioning & history

The canvas edit-history and edit_version model behind deployments.

API overview

Base URLs, request lifecycle, and how every operation is shown three ways.

Roles & permissions

Why deploying requires the owner or admin role.

Publish as an MCP tool

Expose a deployed workflow to external AI clients through ModuleX MCP.