Skip to main content

Data Objects

A data object is a process-level variable with a declared type. It bridges an inline type and the actual runtime value stored in the process instance.

Available in BPMN XML only

These constructs (itemDefinition, dataObject/dataObjectReference, dataStore/dataStoreReference) are parsed only from BPMN 2.0 XML definitions. JSON/YAML process definitions express a subset and cannot declare typed data objects, data stores, or inline types. See the Processes guide for JSON/YAML format limitations.

Two BPMN Elements​

BPMN 2.0 uses two elements together:

  • <bpmn:dataObject> — declared inside <bpmn:process>, names the variable and references its type.
  • <bpmn:dataObjectReference> — a positional "sighting" of that variable at a specific point in the flow. Multiple references can point to the same dataObject.
<bpmn:process id="loan-application" isExecutable="true">

<!-- Declare the typed variables -->
<bpmn:dataObject id="ApplicationData" name="application" itemSubjectRef="Applicant" />
<bpmn:dataObject id="StatusData" name="loan_status" itemSubjectRef="LoanStatus" />

<!-- Place them in the flow -->
<bpmn:dataObjectReference id="ApplicationDataRef" dataObjectRef="ApplicationData" />
<bpmn:dataObjectReference id="StatusDataRef" dataObjectRef="StatusData" />

</bpmn:process>

The name attribute of a dataObject becomes the key in instance.variables. In the example above, instance.variables.application is validated against the Applicant type on every write.

Coexistence with Untyped Variables​

Typed and untyped variables live together in the same variables map. Only variables declared as dataObject are validated — everything else passes through freely:

# "internal_counter" is not declared as a dataObject — it passes through without validation
curl -X POST https://api.stateway.io/v1/instances \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"definition_key": "loan-application",
"variables": {
"application": {
"fullName": "Ana Lima",
"email": "ana@example.com"
},
"internal_counter": 0
}
}'

application is validated against the Applicant schema. internal_counter is stored as-is.

Validation on Write​

Whenever a typed variable is written — at instance creation, task completion, or service task output — Stateway validates the value against the declared type before merging it into instance.variables.

Invalid write example:

curl -X POST https://api.stateway.io/v1/instances \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"definition_key": "loan-application",
"variables": {
"application": {
"fullName": "A",
"email": "not-an-email"
}
}
}'

Response 400 Bad Request:

{
"error": "ValidationError",
"errors": [
{ "path": "application.fullName", "message": "must NOT have fewer than 2 characters" },
{ "path": "application.email", "message": "must match format \"email\"" }
]
}

The instance is not created. No partial state is written.

dataState — Lifecycle Annotation​

Each dataObjectReference optionally carries a dataState attribute. It has no effect on validation or execution — it's an annotation for the human reader:

<bpmn:dataObjectReference
id="ApplicationDataRef_collected"
dataObjectRef="ApplicationData"
dataState="collected" />

<bpmn:dataObjectReference
id="ApplicationDataRef_reviewed"
dataObjectRef="ApplicationData"
dataState="reviewed" />

Using two references for the same dataObject with different states is a BPMN convention for showing lifecycle transitions in the diagram. Both point to the same application variable at runtime.

Collections​

When the referenced itemDefinition has isCollection="true", the variable must be a JSON array, and each element is validated individually:

<bpmn:itemDefinition id="Documents" structureRef="stateway:inline" isCollection="true">
<bpmn:extensionElements>
<stateway:schema kind="object"><![CDATA[
{
"type": "object",
"required": ["name", "url"],
"properties": {
"name": { "type": "string" },
"url": { "type": "string", "format": "uri" }
}
}
]]></stateway:schema>
</bpmn:extensionElements>
</bpmn:itemDefinition>

<bpmn:dataObject id="DocListData" name="documents" itemSubjectRef="Documents" />

Writing documents with a non-array value, or with an array element missing name, produces a ValidationError with the array index in the path (e.g., documents[1].url).

When to Use Typed Variables​

Use typed dataObjectLeave untyped
Business-critical fields (applicant, amount, status)Temporary working variables
Fields shared across multiple tasksOne-off intermediate values
Enum values with a fixed set of valid optionsInternal counters, flags
Fields received from external systemsDebug/logging metadata

You can introduce typed variables incrementally. Adding a dataObject to an existing process only affects the named variable — everything else continues unchanged.