BPMN processes
If a form uses a BPMN diagram, its tasks move through the diagram blocks rather than through steps. In the API, diagram blocks are called nodes, and the arrows between them are called flows.
A task's position in the process is described by tokens. A token is a marker placed on a diagram node that shows where the task currently is and what it's waiting for. A task can have several tokens at once: for example, after an AND gateway, each parallel branch gets its own token. When the branches merge, their tokens complete, and a new token continues along the diagram.
The API methods described in this section let you:
- find out which nodes a task is at and whose action it's waiting for;
- see how a comment moved a task along the diagram;
- approve a task at a specific node, resume a suspended process, or move a token manually;
- get the description of a form's BPMN diagram and the list of its versions;
- find tasks in the form register that are at specific nodes.
- GET/
forms/ {form-id}/ bpmnGet the list of BPMN diagram versions of a form - GET/
forms/ {form-id}/ bpmn/ {bpmn-version}Get a BPMN diagram version of a form
BPMN fields in the form description
The GET /forms and GET /forms/{form-id} methods return two additional fields in the form description:
| use_bpmn_for_new_tasks | Boolean. true means new form tasks are created and move according to the BPMN diagram. |
| bpmn_version | Integer. The number of the diagram version used for new tasks. Returned only if use_bpmn_for_new_tasks = true. |
{
"id": 1204,
"name": "Payment request",
"use_bpmn_for_new_tasks": true,
"bpmn_version": 3
}
BPMN task fields
For tasks based on a BPMN diagram, the GET /tasks/{task-id} method returns additional fields. Tasks that follow regular routing don't have these fields.
| bpmn_version | Integer. The number of the diagram version the task follows. |
| bpmn_suspended | Boolean. true means the task has tokens suspended due to an error. |
| bpmn_tokens | Array of tokens: the nodes the task is currently at. Not returned if there are no tokens. |
The bpmn_tokens element
| token_id | Integer. Token ID. |
| node_id | Integer. ID of the node the token is at. |
| node_name | String. Node name. May be missing. |
| node_type | String. Node type. May be missing. |
| status | String. Token status. |
| person | The user whose action is awaited. May be missing. |
| event_type | String. Awaited event. Returned only for waiting nodes. |
| event_time | Date and time when the event fires. Returned only for Timer nodes. |
GET https://api.pyrus.com/v4 /tasks /91827364
Response body
{
"task": {
"id": 91827364,
"text": "Payment request for invoice No. 4417",
"form_id": 1204,
"bpmn_version": 3,
"bpmn_suspended": false,
"bpmn_tokens": [
{
"token_id": 1,
"node_id": 12,
"node_name": "Legal approval",
"node_type": "Activity",
"status": "Active",
"person": {
"id": 4471,
"first_name": "Mary",
"last_name": "Smith"
}
},
{
"token_id": 2,
"node_id": 18,
"node_name": "Wait 3 business days",
"node_type": "Timer",
"status": "Waiting",
"event_type": "Timer",
"event_time": "2026-09-05T09:00:00Z"
}
]
// ...
}
}
In this example, the task is in two parallel branches at once: in one, it's waiting for legal approval, and in the other, for a timer to fire.
BPMN fields in task comments
If a comment moved a task along the diagram, the comment contains the bpmn_transitions array. If the comment didn't move any tokens, the field is not returned.
The bpmn_transitions element
| token_id | Integer. Token ID. |
| node_id | Integer. ID of the node the token moved to. Not returned if the token completed. |
| node_name | String. Node name. May be missing. |
If an element contains only token_id, the comment completed this token, and the token no longer exists. Tokens that the comment created and immediately completed are not included in the array.
{
"id": 55510293,
"text": "Approved",
"approval_choice": "approved",
"bpmn_transitions": [
{ "token_id": 1 },
{ "token_id": 2 },
{ "token_id": 7, "node_id": 24, "node_name": "Payment" }
]
}
In this example, tokens 1 and 2 completed at the merge gateway, and token 7 continued along the diagram in their place.
Actions on BPMN tasks
The POST /tasks/{task-id}/comments method accepts additional parameters for tasks based on a BPMN diagram. All of them are optional.
| bpmn_node_id | Integer. ID of the node at which you approve the task. Passed together with the approval_choice parameter. |
| bpmn_resume_processing | Boolean. true resumes processing of tokens suspended due to an error. false has no effect. |
| bpmn_token_moves | Array of objects specifying which tokens to move manually and to which nodes. Each object contains two required fields:
|
Approving at a specific node
If a task has split into parallel branches and the user's action is awaited at several nodes at once, specify the node you're acting at in bpmn_node_id.
POST https://api.pyrus.com/v4 /tasks /91827364 /comments
Request body
{
"text": "No objections",
"approval_choice": "approved",
"bpmn_node_id": 12
}
Response body
{
"task": {
"id": 91827364,
"bpmn_version": 3,
"bpmn_suspended": false,
"bpmn_tokens": [
{
"token_id": 1,
"node_id": 20,
"node_name": "Accounting review",
"node_type": "Activity",
"status": "Active",
"person": {
"id": 1731,
"first_name": "Bob",
"last_name": "Johnson"
}
},
{
"token_id": 2,
"node_id": 18,
"node_name": "Wait 3 business days",
"node_type": "Timer",
"status": "Waiting",
"event_type": "Timer",
"event_time": "2026-09-05T09:00:00Z"
}
],
"comments": [
// ...
{
"id": 55510294,
"text": "No objections",
"approval_choice": "approved",
"bpmn_transitions": [
{ "token_id": 1, "node_id": 20, "node_name": "Accounting review" }
]
}
]
// ...
}
}
Resuming after an error
If a token was suspended due to an error ("status": "Suspended", and the task has "bpmn_suspended": true), fix the cause and resume processing. The token continues from the same node.
POST https://api.pyrus.com/v4 /tasks /91827364 /comments
Request body
{
"text": "Bot access granted, resuming",
"bpmn_resume_processing": true
}
Response body
{
"task": {
"id": 91827364,
"bpmn_version": 3,
"bpmn_suspended": false,
"bpmn_tokens": [
{
"token_id": 3,
"node_id": 15,
"node_name": "Upload invoice",
"node_type": "Activity",
"status": "Active"
}
],
"comments": [
// ...
{
"id": 55510295,
"text": "Bot access granted, resuming"
}
]
// ...
}
}
Moving tokens manually
You can move a token to another node, bypassing the routing conditions. You can move several tokens in one comment.
POST https://api.pyrus.com/v4 /tasks /91827364 /comments
Request body
{
"text": "Returning for revision",
"bpmn_token_moves": [
{ "token_id": 1, "node_id": 8 }
]
}
Response body
{
"task": {
"id": 91827364,
"bpmn_version": 3,
"bpmn_suspended": false,
"bpmn_tokens": [
{
"token_id": 1,
"node_id": 8,
"node_name": "Prepare request",
"node_type": "Activity",
"status": "Active",
"person": {
"id": 1731,
"first_name": "Bob",
"last_name": "Johnson"
}
}
],
"comments": [
// ...
{
"id": 55510296,
"text": "Returning for revision",
"bpmn_transitions": [
{ "token_id": 1, "node_id": 8, "node_name": "Prepare request" }
]
}
]
// ...
}
}
curl
curl -X POST \
'https://api.pyrus.com/v4/tasks/91827364/comments' \
-H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{
"text": "Returning for revision",
"bpmn_token_moves": [
{ "token_id": 1, "node_id": 8 }
]
}'
Note: you can't move a token to the node it's already at, and you can't move it from one parallel branch to another. The bpmn_resume_processing and bpmn_token_moves actions are not performed in a closed task — reopen it first.
Filtering the form register by diagram nodes
The GET /forms/{form-id}/register method accepts two additional parameters for forms with a BPMN diagram. You can combine them with other register filters.
| bpmn_nodes | Diagram node IDs. Only tasks with at least one token at one of the specified nodes are returned. In a GET request, pass the IDs separated by commas; in a POST request, pass them as an array. If the parameter is missing or empty, the filter is not applied. |
| bpmn_suspended | true (or y) returns only tasks with tokens suspended due to an error; false (or n) returns only tasks without such tokens. If the parameter is missing, the filter is not applied. |
GET request example:
GET https://api.pyrus.com/v4/forms/1204/register?bpmn_nodes=12,18
The same as a POST request, with the parameters in the request body:
{
"bpmn_nodes": [12, 18],
"bpmn_suspended": false
}
Nodes in the list are combined with OR: it's enough for a token to be at any of them. If you specify the ID of a node that doesn't exist, you won't get an error, but the result will be empty.
Tip: you can get node IDs using the GET /forms/{form-id}/bpmn/{bpmn-version} method.
GET /forms/{form-id}/bpmn
This method returns the list of BPMN diagram versions of a form. It's available to anyone with access to the form.
GET https://api.pyrus.com/v4 /forms /1204 /bpmn
Response body
{
"form_id": 1204,
"active_bpmn_version": 3,
"versions": [
{
"bpmn_version": 4,
"description": "Draft with legal review",
"create_date": "2026-09-20T08:15:00Z",
"author": {
"id": 4471,
"first_name": "Mary",
"last_name": "Smith",
"type": "user"
}
},
{
"bpmn_version": 3,
"create_date": "2026-08-01T10:00:00Z"
}
]
}
curl
curl -X GET \ 'https://api.pyrus.com/v4/forms/1204/bpmn' \ -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
Response fields
| form_id | Integer. Form ID. |
| active_bpmn_version | Integer. The number of the version used for new tasks. Returned only if the form has use_bpmn_for_new_tasks = true. |
| versions | Array of diagram versions in descending order of number, including deleted ones. An empty array if there are no versions. Each version contains the following fields:
|
GET /forms/{form-id}/bpmn/{bpmn-version}
This method returns the description of the specified BPMN diagram version of a form: nodes, flows between them, field visibility conditions, and text frames. It's available to anyone with access to the form.
Every form always has version 0: until it's saved, it's returned empty. A deleted version is returned too, with the delete_date field. Empty arrays are not included in the response.
GET https://api.pyrus.com/v4 /forms /1204 /bpmn /3
Response body
{
"form_id": 1204,
"bpmn_version": 3,
"active_bpmn_version": 3,
"create_date": "2026-08-01T10:00:00Z",
"active_task_nodes": [12],
"nodes": [
{
"id": 1,
"node_type": "Start",
"position": { "x": 40, "y": 200 },
"flows": [ { "id": 1, "to_node_id": 12 } ]
},
{
"id": 12,
"node_type": "Activity",
"description": "Legal approval",
"participant": {
"person": {
"id": 4471,
"first_name": "Mary",
"last_name": "Smith",
"type": "user"
}
},
"actions": ["Approve", "Reject"],
"position": { "x": 240, "y": 200 },
"flows": [ { "id": 2, "to_node_id": 2 } ]
},
{
"id": 2,
"node_type": "Finish",
"position": { "x": 440, "y": 200 }
}
],
"field_visibility_conditions": [
{
"field_id": 7,
"condition": { "field_id": 5, "condition_type": 3 }
}
]
}
curl
curl -X GET \ 'https://api.pyrus.com/v4/forms/1204/bpmn/3' \ -H 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
Response fields
| form_id | Integer. Form ID. |
| bpmn_version | Integer. Version number. |
| active_bpmn_version | Integer. The number of the version used for new tasks. Returned only if the form has use_bpmn_for_new_tasks = true. |
| description | String. Version description. May be missing. |
| create_date | Version creation date. Not returned for an unsaved version 0. |
| delete_date | Version deletion date. Returned only for deleted versions. |
| author | The user who created the version. May be missing. |
| active_task_nodes | Array of integers. IDs of nodes where task tokens are currently located. |
| nodes | Array of diagram nodes. |
| deleted_nodes | Array of deleted nodes. Tasks may still be moving through them, and tokens in bpmn_tokens may refer to them. |
| field_visibility_conditions | Array of form field visibility conditions in this version. Each element contains the following fields:
|
| frames | Array of text frames on the diagram. Each frame contains the following fields:
|
The nodes element
The format is the same for the nodes and deleted_nodes arrays.
| id | Integer. Node ID. Matches node_id in bpmn_tokens and bpmn_transitions. |
| node_type | String. Node type. |
| description | String. Node name. May be missing. |
| participant | Object: the participant whose action is awaited. |
| subprocess_configuration | Object: subprocess settings. Returned only for Subprocess nodes. |
| timer | Object: timer settings. Returned only for Timer nodes. |
| awaiting_statuses | Array of integers. Task statuses the node waits for. Returned only for AwaitingStatus nodes. |
| task_status | Integer. The status assigned to the task when it reaches the node. |
| actions | Array of strings. Actions available to the participant: Approve, Reject, Acknowledge, Complete, Sign. |
| reference_node_id | Integer. The related node: for an AND_Split node, its matching AND_Join node. |
| flow_group_id | Integer. The AND gateway branch the node belongs to. |
| position | Object. Node coordinates on the diagram: x, y. |
| flows | Array of outgoing flows. |
| deleted_flows | Array of deleted outgoing flows. |
The participant element
| person | Object: a user, role, or bot. The format is the same as for a user; the type is specified in the type field. |
| contact_field_id | Integer. The Contact field the participant is taken from. |
| contact_field_form_field_id | Integer. The field of the linked form, if the contact is taken from it. |
| queue_node_id | Integer. The queue node the participant is taken from. |
| workflow_catalog_column | Object. The participant is taken from a catalog column. Contains the catalog_id, column_id, column_name, field_id, and is_manager fields. |
| workflow_by_department_column | Object. The participant is taken from the org chart. Contains the catalog_id, column_id, and column_name fields, as well as apply_to_task_author or contact_field_id. |
The flows element
The format is the same for the flows and deleted_flows arrays.
| id | Integer. Flow ID. |
| to_node_id | Integer. ID of the node the flow leads to. |
| condition | Object: the transition condition. May be missing. |
| is_default | Boolean. The default transition of an XOR gateway. Returned only if true. |
| vertex_no | Integer. The gateway vertex the flow leaves from. |
| to_vertex_no | Integer. The gateway vertex the flow enters. |
| hint_position | Object. Coordinates of the condition label on the diagram: x, y. |
The timer element
| mode | String. How time is counted: RelativeTime — calendar time, RelativeOrgWorkTime — the organization's working hours. |
| days | Integer. Days. |
| hours | Integer. Hours. |
| minutes | Integer. Minutes. |
The subprocess_configuration element
The format is the same as for subprocess settings in the form description.
| subprocess_form_id | Integer. ID of the subprocess form. |
| wait_until_subprocess_finished | Boolean. Whether to wait for the subprocess to finish. |
| field_mappings | Array. Mapping between the fields of the main form and the subprocess form. |
| update_main_fields_mode | String. When to update the main task fields. |
| update_main_fields_on_step | Integer. The step at which the main task fields are updated. |
| finish_subprocess_tasks_when_main_is_finished | Boolean. Whether to close subprocess tasks together with the main task. |
| subprocess_guid | String. ID of the subprocess setting. |
| map_changes_only_on_subprocess_step | Boolean. Transfer changes only at the subprocess step. |
The condition element
The format is the same as for routing conditions in the form description.
| field_id | Integer. The form field the condition checks. |
| condition_type | Integer. Condition type. |
| value | String. The value to compare with. |
| values | Array of strings. The values to compare with. |
| catalog_column | Integer. Catalog column. Only for catalog fields. |
| children | Array of nested conditions. |
Enumeration values
Token status (status)
| Active | The token is waiting for a user's action. |
| Waiting | The token is waiting for an event: a timer firing or the task reaching a certain status. |
| Completed | The token has reached the end of the process. |
| Suspended | The token was suspended due to an error. To continue, use the bpmn_resume_processing parameter. |
| Terminated | The task was forcibly closed. |
Node type (node_type)
| Start | Process start. |
| Finish | Process finish. |
| Activity | Action. |
| XOR | XOR gateway. |
| AND_Split | Split AND gateway. |
| AND_Join | Merge AND gateway. |
| Subprocess | Subprocess. |
| Queue | Queue. |
| Timer | Timer (waiting for a period of time). |
| AwaitingStatus | Timer (awaiting status). |
Learn more about diagram blocks in BPMN workflow.
Awaited event (event_type)
| Timer | A timer fires. |
| AwaitingStatus | The task reaches the required status. |
Error codes
| Code | Description |
|---|---|
| bpmn_token_not_found | The token wasn't found in the task, or there is no action awaiting your approval at the specified node. Occurs if bpmn_token_moves contains a non-existent token_id, or if bpmn_node_id passed with approval_choice points to a node where you have no active action. |
| bpmn_node_not_found | The process diagram has no node to move the token to. Occurs if bpmn_token_moves contains an invalid node_id. |
| bpmn_invalid_token_move | The token can't be moved: the target node is the same as the current one, the diagram structure doesn't allow the move (for example, from one parallel branch to another), or the same token_id is specified twice in the request. |
| bpmn_engine_failure | The task's process diagram couldn't be processed. This usually means the form or the diagram was deleted, or the diagram version is unavailable. May occur during any action on a BPMN task. |
| bpmn_task_closed | The task is closed. The bpmn_resume_processing and bpmn_token_moves actions are not performed in a closed task — reopen it first. |
| bpmn_diagram_version_not_found | The form doesn't have the specified diagram version. Occurs in the GET /forms/{form-id}/bpmn/{bpmn-version} method. |
| access_denied_form | No access to the form (HTTP 403). Occurs in the GET /forms/{form-id}/bpmn and GET /forms/{form-id}/bpmn/{bpmn-version} methods. |
Note: apps that use the PyrusApiClient library version 2.1.11.1 or earlier get the server_error error instead of these codes.