Starting a workflow
This guide shows how to start an enaio workflow through the API, including input variables and an attached file. The bundled standard ad-hoc workflow serves as the running example.
The flow has four steps:
-
Discover the workflow, client type and workflow user.
-
Determine the workflow’s input variables.
-
Create a document with a file in the DMS.
-
Start the workflow, passing the variables and the document.
|
A file is not uploaded directly at start time. Instead, the document (with its file) is first created in the DMS and then referenced by its object ID as an |
1. Connection
from ecmind_blue_client.ecm import ECM
from ecmind_blue_client.pool import SyncPoolClient
ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="<user>", password="<pass>"))
Async (AsyncPoolClient) works the same way with await in front of the calls.
2. Step 1: Discovery
start_process needs three identifiers: the workflow user (workflow-organisation GUID, not the security user), a client type, and the workflow.
# Resolve the workflow user from a login name
user = ecm.workflow.organisation_user_by_login("root")
# Available client types (the name is enough for the following calls)
client_type = "#OSECM_Client#" # see ecm.workflow.client_types()
# Startable workflows for this user and client type
workflows = ecm.workflow.workflow_list(user, client_type)
adhoc = next(wf for wf in workflows if wf.name == "Standard-Ad-hoc-Workflow")
|
Looking the workflow up by its stable display name ( |
3. Step 2: Determine input variables
The workflow definition decides which variables may be set at start time (the "input variable" flag). workflow_model_by_name() returns a typed model whose fields are exactly those input variables.
Variables = ecm.workflow.workflow_model_by_name(adhoc.model_name, user, client_type)
# the fields of Variables = the workflow's input variables
The standard ad-hoc workflow has five input variables: sAntragsteller, lLaufliste, sSubject (each IN) plus sBemHist and lAbstimmungsergebnis (each INOUT). Pure output variables (OUT, e.g. iFreigabe) and internal process variables that the workflow fills itself are not meant to be set at start time. Pass include_internal=True to also list the internal variables for inspection.
What matters is the workflow process interface: a variable can be set at start time when it is declared there as an IN or INOUT parameter.
4. Step 3 (optional): Generate typed models
For full IDE support and type checking, the models can be generated as .py files instead of being resolved at runtime.
# Document models of the cabinet
ecm-generate-models \
--host enaio.example.com --username <user> --password <pass> \
--cabinet <cabinet> --output-dir ./models
# Workflow variable model
ecm-generate-workflow-models \
--host enaio.example.com --username <user> --password <pass> \
--client-type "#OSECM_Client#" \
--workflow "Ad-hoc Version 3.0.5" --output-dir ./wf_models
The generated workflow model lists the input variables explicitly as class attributes:
# wf_models/... (DO NOT EDIT - regenerate)
from ecmind_blue_client.ecm import ECMWorkflowModel, ECMWorkflowRecordModel
class LAbstimmungsergebnisRecord(ECMWorkflowRecordModel):
"""Generated record model."""
Kategorie: str | None = None
Anzahl: int | None = None
class LLauflisteRecord(ECMWorkflowRecordModel):
"""Generated record model."""
AktivitaetId: str | None = None
class Standard_Ad_hoc_WorkflowModel(ECMWorkflowModel):
"""Input variables for the 'Ad-hoc Version 3.0.5' workflow."""
sBemHist: str | None = None
sAntragsteller: str | None = None
sSubject: str | None = None
lAbstimmungsergebnis: list[LAbstimmungsergebnisRecord] | None = None
lLaufliste: list[LLauflisteRecord] | None = None
|
The class name is derived from the workflow’s stable display name ( |
5. Step 4: Create a document with a file
The document is created with its file in the DMS; insert() returns the object ID and the object type ID.
from ecmind_blue_client.ecm.model import make_document_model
from ecmind_blue_client.rpc import JobRequestFileFromBytes
# TODO: adjust document type and storage location to the target cabinet
Document = make_document_model("Dokument")
object_id, object_type_id = ecm.dms.insert(
Document(),
files=[JobRequestFileFromBytes(b"Sample file content.\n", "txt")],
folder_id=42,
)
6. Step 5: Start the workflow
from ecmind_blue_client.ecm import ECMWorkspaceDocument
process_id = ecm.workflow.start_process(
user=user,
workflow=adhoc, # ECMWorkflow object from step 1
client_type=client_type,
variables={
"sAntragsteller": "ROOT", # IN
"sSubject": "Approval offer 2026-001", # IN
"sBemHist": "Ad-hoc start via API with an attached document.", # INOUT
},
documents=[ECMWorkspaceDocument(id=object_id, type=object_type_id)],
)
print(f"Workflow started, ProcessId: {process_id}")
variables accepts a plain mapping (string values are sent as strings and the server converts them) or a typed model instance from step 3. Prefer the typed model for dates, times, lists and records, since it handles the correct serialisation.
7. Complete example
from ecmind_blue_client.ecm import ECM, ECMWorkspaceDocument
from ecmind_blue_client.ecm.model import make_document_model
from ecmind_blue_client.pool import SyncPoolClient
from ecmind_blue_client.rpc import JobRequestFileFromBytes
CLIENT_TYPE = "#OSECM_Client#"
ADHOC_NAME = "Standard-Ad-hoc-Workflow" # stable display name
ecm = ECM(SyncPoolClient(servers="enaio.example.com:4000:1", username="<user>", password="<pass>"))
# 1. Discovery
user = ecm.workflow.organisation_user_by_login("root")
adhoc = next(wf for wf in ecm.workflow.workflow_list(user, CLIENT_TYPE) if wf.name == ADHOC_NAME)
# 2. Create a document with a file (TODO: adjust document type and storage location)
Document = make_document_model("Dokument")
object_id, object_type_id = ecm.dms.insert(
Document(),
files=[JobRequestFileFromBytes(b"Sample file content.\n", "txt")],
folder_id=42,
)
# 3. Start the workflow: parameters + document in the workspace
process_id = ecm.workflow.start_process(
user=user,
workflow=adhoc,
client_type=CLIENT_TYPE,
variables={
"sAntragsteller": "ROOT", # IN
"sSubject": "Approval offer 2026-001", # IN
"sBemHist": "Ad-hoc start via API with an attached document.", # INOUT
},
documents=[ECMWorkspaceDocument(id=object_id, type=object_type_id)],
)
print(f"Workflow started, ProcessId: {process_id}")
8. Related topics
-
start_process() for all parameters, variable value formats and server specifics
-
ecm-generate-workflow-models for typed workflow variable models
-
ecm-generate-models for typed document models
-
insert() for creating the document with a file