Skip to main content
Version: 1.12.x (Next)

Workflow API (Beta)

Beta Feature

The Workflow API is currently in Beta. The API endpoints and response formats may change in future releases.

The Workflow API provides programmatic access to execute Langflow workflows in sync, stream, or background modes.

The Workflow API is part of the Langflow Developer v2 API and offers enhanced workflow execution capabilities compared to the v1 /run endpoint.

As of Langflow version 1.11, stream mode supports both Langflow's built-in EventManager and the AG-UI protocol.

New to the Workflow API?

Start with the Workflow API quickstart for a step-by-step walkthrough of sync, stream, and background modes.

Prerequisites

  • Install and start Langflow with the developer API enabled

    The Workflow API endpoints require the developer_api_enabled setting to be enabled. If this setting is disabled, these endpoints will return a 404 Not Found error.

    To enable the developer API endpoint, do the following:

    1. In the Langflow .env file, set the environment variable to true:
      LANGFLOW_DEVELOPER_API_ENABLED=true
    2. Start your Langflow server with the .env file enabled:
      uv run langflow run --env-file .env

    For more information about configuring environment variables, see Environment variables.

  • Create a Langflow API key

  • Create a flow that you want to execute

  • Get the flow ID or endpoint name of the flow you want to execute

Set environment variables

All code examples in this documentation assume you have set the following environment variables:

Python:

import os

LANGFLOW_SERVER_URL = os.getenv("LANGFLOW_SERVER_URL")
LANGFLOW_API_KEY = os.getenv("LANGFLOW_API_KEY")

TypeScript/JavaScript:

const LANGFLOW_SERVER_URL = process.env.LANGFLOW_SERVER_URL;
const LANGFLOW_API_KEY = process.env.LANGFLOW_API_KEY;

Set these environment variables before running the examples, or replace the variable references in the code examples with your actual Langflow server URL and API key.

The default LANGFLOW_SERVER_URL for a local Langflow deployment is http://localhost:7860. For remote deployments, the domain is set by your hosting service, such as https://UUID.ngrok.app.

Authentication and headers

All Workflow API requests require authentication using a Langflow API key. The API key is passed in the x-api-key header.

For more information, see Create a Langflow API key.

HeaderDescriptionExample
Content-TypeSpecifies the JSON format.application/json
x-api-keyYour Langflow API key.sk-...
acceptOptional. Specifies the response format.application/json

Execute workflow endpoint

Endpoint:

POST /api/v2/workflows

Description: Execute a workflow in sync, stream, or background mode.

Request body

FieldTypeRequiredDefaultDescription
flow_​idstringYes-UUID of the flow to execute.
input_​valuestringNo""Chat-style input for the run.
modestringNosyncExecution mode: sync, stream, or background.
stream_​protocolstringNolangflowStream adapter name used for stream responses and background event re-attachment. Unknown values return a 422 code for any request mode because the API validates the field against the registered adapters before execution starts.
session_​idstringNo-Scopes message memory and chat history to this session.
tweaksobjectNo{}Per-component parameter overrides keyed by component id. See Component tweaks.
globalsobjectNo{}Request-level global variables. Available in sync mode only. Keys are limited to 256 characters and values to 64 KB. See Pass request-level global variables.
output_​idsarrayNo-Output component ids to use when resolving sync-mode answers (sync mode only).
dataobjectNo-Live-canvas override of nodes and edges (stream and background modes only).
filesarrayNo-Pre-uploaded file paths to attach to the run (stream and background modes only).
start_​component_​idstringNo-Partial-run start component id (stream and background modes only).
stop_​component_​idstringNo-Partial-run stop component id (stream and background modes only).

Execute flow in sync mode

Set "mode": "sync" or omit mode to run inline and receive the full response when execution completes.

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

payload = {
"flow_id": flow_id,
"input_value": "what is 2+2",
"session_id": "session-123",
"mode": "sync",
"globals": {
"FILENAME": "relatório—final.pdf",
"OWNER_NAME": "José",
},
}

response = requests.post(f"{base}/api/v2/workflows", headers=headers, json=payload, timeout=120)
response.raise_for_status()
print(response.text)

Execute flow with selected stream mode

Set "mode": "stream" to receive a Server-Sent Events (SSE) stream for the run.

stream_protocol is set to langflow by default, which emits the built-in Langflow EventManager output. For more information, see Stream with Langflow EventManager

Set stream_protocol to agui to emit events using the AG-UI protocol instead. For more information, see Stream with AG-UI.

If stream_protocol names an unknown adapter, the endpoint returns 422 with an available list of registered protocol names.

Stream with Langflow EventManager

stream_protocol defaults to langflow, which passes through the built-in Langflow EventManager events. Each SSE frame has a monotonic id: and a data: line containing JSON shaped like {"event": "<type>", "data": {...}}. This is the same wire format the v1 build stream uses, so existing Langflow clients can read it without changes.

Omit stream_protocol or set it explicitly to "langflow". Use curl -N so the client does not buffer the stream.

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "67ccd2be-17f0-8190-81ff-3bb2cf6508e6")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

payload = {
"flow_id": flow_id,
"input_value": "Hello from a Langflow stream client",
"mode": "stream",
"session_id": "session-123",
}

with requests.post(
f"{base}/api/v2/workflows",
headers=headers,
json=payload,
stream=True,
timeout=120,
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if line:
print(line)

Common EventManager event types:

EventPurpose
vertices_​sortedExecution order for the flow's components.
add_​messageChat message added (user or assistant).
tokenStreaming LLM token chunk (data.chunk).
end_​vertexA component finished building.
outputNormalized terminal component output (same shape as sync-mode outputs).
endRun finished successfully.
errorRun failed (data.error).
cancelledRun stopped by the client.

For more examples of token and add_message events, see Stream LLM token responses.

Stream with AG-UI

Stream with the AG-UI protocol when your client expects agent lifecycle events such as RUN_STARTED and TEXT_MESSAGE_* instead of Langflow's internal events. Read responses as an SSE stream. Each data: line contains one AG-UI event serialized as JSON. Close flow runs when you receive RUN_FINISHED, or handle failures on RUN_ERROR.

Send POST /api/v2/workflows with "mode": "stream" and "stream_protocol": "agui".

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "67ccd2be-17f0-8190-81ff-3bb2cf6508e6")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

payload = {
"flow_id": flow_id,
"input_value": "Hello from an AG-UI client",
"mode": "stream",
"stream_protocol": "agui",
"session_id": "thread-123",
}

with requests.post(
f"{base}/api/v2/workflows",
headers=headers,
json=payload,
stream=True,
timeout=120,
) as response:
response.raise_for_status()
for line in response.iter_lines(decode_unicode=True):
if line:
print(line)

Common AG-UI event types:

Event typePurpose
RUN_​STARTED / RUN_​FINISHED / RUN_​ERRORRun lifecycle.
TEXT_​MESSAGE_​START / TEXT_​MESSAGE_​CONTENT / TEXT_​MESSAGE_​ENDStreaming assistant text.
TOOL_​CALL_​START / TOOL_​CALL_​ARGS / TOOL_​CALL_​END / TOOL_​CALL_​RESULTTool invocation lifecycle.
STEP_​STARTED / STEP_​FINISHEDPer-component execution steps.
STATE_​SNAPSHOT / STATE_​DELTANode graph state (status and output).
CUSTOMLangflow-specific extensions (see below).

Langflow also emits CUSTOM events that generic AG-UI clients can ignore, such as langflow.log, langflow.content.*, langflow.message.removed, and langflow.run.cancelled.

For the full AG-UI event catalog, see the AG-UI specification.

For a longer client example that parses AG-UI frames and chains two runs in one session_id, see example-stream-agui-parse.py (and matching .js / .sh files) under docs/docs/API-Reference/.

Execute flow in background mode

Set "mode": "background" to queue a job and receive a job_id immediately. Poll GET /api/v2/workflows for status and results, re-attach to the event stream with GET /api/v2/workflows/{job_id}/events, or stop the job with POST /api/v2/workflows/stop.

Background runs honor the stream_protocol selected when the job was created.

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

payload = {
"flow_id": flow_id,
"input_value": "Process this in the background",
"session_id": "session-456",
"mode": "background",
}

response = requests.post(f"{base}/api/v2/workflows", headers=headers, json=payload, timeout=60)
response.raise_for_status()
print(response.text)

See Background response fields in Response body for the job object returned when you queue a background run.

Re-attach to a background run

Endpoint: GET /api/v2/workflows/{job_id}/events (also returned as links.events on the background job response)

You can replay buffered SSE events from a background run and tail the stream until the job finishes.

Each SSE frame includes an id: line. Pass the last id value you received in a Last-Event-ID header to resume from the next event.

headers = {
"x-api-key": api_key,
"Accept": "text/event-stream",
"Last-Event-ID": last_event_id,
}

Response body

The response shape depends on the selected mode.

stream mode returns Server Sent Events. For more information, see Execute flow with selected stream mode.

sync mode returns a completed WorkflowExecutionResponse, for example:

{
"flow_id": "67ccd2be-17f0-8190-81ff-3bb2cf6508e6",
"session_id": "session-123",
"job_id": "a98d9753-9259-47ca-9783-69a9d8d26889",
"object": "response",
"created_timestamp": "2026-06-30T16:00:56.917538+00:00",
"status": "completed",
"output": {
"reason": "single",
"text": "2 + 2 equals 4.",
"source": "ChatOutput-xyz"
},
"has_errors": false,
"errors": [],
"inputs": {},
"globals": {
"FILENAME": "relatório—final.pdf",
"OWNER_NAME": "José"
},
"outputs": {
"ChatOutput-xyz": {
"type": "message",
"status": "completed",
"display_name": "Chat Output",
"content": "2 + 2 equals 4."
}
}
}

Sync response fields

FieldDescription
outputPrimary text answer for the run.
output.reasonWhy output.text was or wasn't populated: single, multiple, none, non_​string, or failed.
output.textThe answer when output.reason is single; otherwise null.
output.sourceComponent id that produced output.text when output.reason is single.
outputsMap of component id → component result.
has_​errorstrue when errors is non-empty.
created_​timestampISO-8601 UTC timestamp (not a Unix epoch).
session_​idSession used for the run; pass it on the next request to continue the same chat history.

Each value in outputs includes:

FieldDescription
typeContent type (message, image, sql, data, file, etc.).
statusComponent run status (completed, failed, …).
display_​nameHuman-readable component name.
contentComponent payload.
metadataOptional extra metadata for the component output.

Background response fields

background mode returns a job object immediately (object: "job"). Poll GET /api/v2/workflows until the job completes; the completed result uses the same WorkflowExecutionResponse shape as sync mode (see the example above).

{
"job_id": "a98d9753-9259-47ca-9783-69a9d8d26889",
"flow_id": "67ccd2be-17f0-8190-81ff-3bb2cf6508e6",
"object": "job",
"created_timestamp": "2026-06-30T16:00:56.917538+00:00",
"status": "queued",
"links": {
"status": "/api/v2/workflows?job_id=a98d9753-9259-47ca-9783-69a9d8d26889",
"events": "/api/v2/workflows/a98d9753-9259-47ca-9783-69a9d8d26889/events",
"stop": "/api/v2/workflows/stop"
},
"errors": [],
"globals": {}
}
FieldDescription
objectAlways "job".
job_​idUUID for polling, re-attaching to events, and stop requests.
links.statusGET /api/v2/workflows?job_​id=…
links.eventsGET /api/v2/workflows/{job_​id}/events
links.stopPOST /api/v2/workflows/stop

Get workflow status endpoint

Endpoint: GET /api/v2/workflows

Description: Retrieve the status and results of a workflow execution by job ID.

Example request

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

start = requests.post(
f"{base}/api/v2/workflows",
headers=headers,
json={
"flow_id": flow_id,
"input_value": "Process this in the background",
"mode": "background",
},
timeout=60,
)
start.raise_for_status()
print(start.text)

Query parameters

ParameterTypeRequiredDescription
job_​idstringYesThe job ID returned from a workflow execution.

Example response

{
"flow_id": "67ccd2be-17f0-8190-81ff-3bb2cf6508e6",
"session_id": "session-123",
"job_id": "a98d9753-9259-47ca-9783-69a9d8d26889",
"object": "response",
"created_timestamp": "2026-06-30T16:00:56.917538+00:00",
"status": "completed",
"output": {
"reason": "single",
"text": "Processing complete...",
"source": "ChatOutput-xyz"
},
"has_errors": false,
"errors": [],
"inputs": {},
"globals": {},
"outputs": {
"ChatOutput-xyz": {
"type": "message",
"status": "completed",
"display_name": "Chat Output",
"content": "Processing complete..."
}
}
}

Response body

Returns one of two JSON schemas depending on job state:

Job stateResponseNotes
queued, in_​progress, cancelledWorkflowJobResponseSame shape as a background job create response (object: "job", links, …).
completedWorkflowExecutionResponseFull results (example above).
failedHTTP 500Error detail in the response body; not a workflow result object.
timed_​outHTTP 408Error detail in the response body.

When the job is still active, poll GET /api/v2/workflows?job_id=… or re-attach to events for live output.

The status values are:

StatusDescription
queuedJob is queued and waiting to start.
in_​progressJob is currently executing.
suspendedJob is paused and waiting for human input. See Human-in-the-Loop.
completedJob completed successfully.
failedJob failed during execution.
cancelledJob was stopped by the client.
timed_​outJob exceeded the execution timeout.

Stop workflow endpoint

Endpoint: POST /api/v2/workflows/stop

Description: Stop a running workflow execution by job ID.

Example request

import os

import requests

base = os.environ.get("LANGFLOW_URL") or os.environ.get("LANGFLOW_SERVER_URL", "")
flow_id = os.environ.get("FLOW_ID", "")
api_key = os.environ.get("LANGFLOW_API_KEY", "")

headers = {"Content-Type": "application/json", "x-api-key": api_key}

start = requests.post(
f"{base}/api/v2/workflows",
headers=headers,
json={
"flow_id": flow_id,
"input_value": "Process this in the background",
"mode": "background",
},
timeout=60,
)
start.raise_for_status()
job_id = start.json()["job_id"]

stop = requests.post(
f"{base}/api/v2/workflows/stop",
headers=headers,
json={"job_id": job_id},
timeout=60,
)
print(stop.status_code, stop.text)

Request body

FieldTypeRequiredDefaultDescription
job_​idstringYes-The job ID of the workflow to stop.

Example response

{
"job_id": "job_id_1234567890",
"message": "Job job_id_1234567890 cancelled successfully."
}

Pass request-level global variables

Pass request-scoped variables in the globals JSON field. They are available to workflow components for the duration of the run.

Use globals when values are large, shared across runs, or would exceed HTTP header size limits. Tweaks are better suited for one-off component overrides. globals is keyed by variable name and not component ID, so it stays stable when the UI regenerates node IDs when importing flows.

globals is honored in sync mode only; stream and background runs ignore it. The Workflow API is in Beta, and this transport may continue to evolve.

Use a stable name in the UI and then pass it in globals

To avoid depending on changing component IDs, rename a component, create a matching global variable, bind the field, and pass the value in the request.

  1. To rename the component in the UI, click Edit, and then rename the component. This example uses CUSTOMER_PROMPT.
  2. Save the flow.
  3. Create a new global variable with the same name as the component, such as CUSTOMER_PROMPT, and save it. For more about creating global variables, see Global variables.
  4. In the field you want to fill at runtime, click the Globe icon, select CUSTOMER_PROMPT, and save the flow.
  5. Call the v2 Workflow API in sync mode and pass the value in globals.
curl -X POST "http://localhost:7860/api/v2/workflows" \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{
"flow_id": "YOUR_FLOW_ID",
"mode": "sync",
"input_value": "hello",
"globals": {
"CUSTOMER_PROMPT": "The prompt with many words..."
}
}'
Legacy: X-LANGFLOW-GLOBAL-VAR-* headers (Workflow API, sync mode only)

If you integrated against an earlier Workflow API preview, X-LANGFLOW-GLOBAL-VAR-* headers still work for sync runs on POST /api/v2/workflows. The server merges them with body globals; when the same key is sent both ways, the body value wins.

Prefer the globals body field for new integrations. Header-based globals may be removed in a future release.

This note applies to the Workflow API only. The v1 /run and /responses endpoints still document X-LANGFLOW-GLOBAL-VAR-* headers as their normal transport for request-level variables.

Component tweaks

Use the tweaks object for one-off component parameter overrides in a single run.

{
"flow_id": "67ccd2be-17f0-8190-81ff-3bb2cf6508e6",
"input_value": "what is 2+2",
"tweaks": {
"LLMComponent-123": {
"temperature": 0.7,
"max_tokens": 100
}
}
}

For more information, see Tweaks (API inputs).

Error handling

The API uses standard HTTP status codes to indicate success or failure:

Status CodeDescription
200 OKRequest successful.
400 Bad RequestInvalid request parameters.
403 ForbiddenInvalid or missing API key.
404 Not FoundFlow not found or developer API disabled.
422 Unprocessable EntityUnknown stream_​protocol or unsupported field for the selected mode.
500 Internal Server ErrorServer error during execution.
501 Not ImplementedEndpoint not yet implemented.

Error response format

{
"detail": "Error message describing what went wrong"
}

For an unknown stream_protocol, the 422 response includes an available list of registered protocol names (langflow, agui).

See also

Was this page helpful?

Support
Search