Block reference¶
Every block this pack contributes, with the config it takes and the output it produces. The
tables are the two JSON Schemas each block publishes into the catalog -- the same ones
GET /blocks serves, the same ones the UI builds its step form from.
What a block is, and the contract behind these tables, is dirigent's own. The short version:
- An operator does work. It either finishes and returns its output, or hands back a handle
for the engine to probe, which is how
dhis2.analytics_runwaits out a table rebuild without holding a worker for the length of it. - A sensor waits for the world. Each poke is one short, read-only observation, and "not
yet" is the expected answer rather than a failure.
poll,deadlineandon_timeoutare step-level engine semantics, uniform across every sensor and never in a block's own config.
Every block here declares the dhis2 group, and every one takes a connection naming a
dhis2 connection by its code.
Idempotent says whether re-running the block after an unclear failure is safe. The engine
spends the step's retry budget either way, so this is what to read before writing
max_attempts above 1. No block in this pack runs code on the worker, so none has to be
allowlisted.
How an output is shaped¶
The blocks answer in one shape per kind of work, so a reference reads the same field whichever sibling produced it:
- A read of one collection answers its rows under
rows, a list of objects, and apagerwhen the read is paged:page,page_size,totalandpage_countwhen the instance counted them, andmore, which says whether rows match past the ones read. That isdhis2.metadata,dhis2.tracker,dhis2.analytics_queryanddhis2.sql_view, anddhis2.data_storeanswers a namespace's keys the same way. - A read of several collections answers
collections, each one's rows under its own name, andtotals, each one's row count under its name, the way a paged read'spager.totalcounts its rows. That isdhis2.metadata_export, and itscollectionsis a metadata bundle as it stands, whichdhis2.metadata_importtakes whole. bodycarries a DHIS2 document as the instance wrote it, and only where the document is itself the thing to hand on: the data value setdhis2.data_value_set_exportreads, which an import takes whole, and the analytics grid beside itsrows, for itsheadersandmetaData.- Text a block does not parse, a data value set exported as CSV, XML or ADX, is written
whole to the run's storage at
uri, and its head is inlined astext, cut at the instance's inline capture size, withtruncatedandcontent_bytessaying how much there is. - An import answers its summary's
status, whether it was adry_run, how many objects itsent,countsholdingimported,updated,ignoredanddeleted, theobjectsthe summary names, and itsconflicts. That isdhis2.data_value_set_import,dhis2.metadata_importanddhis2.tracker_import; a data value summary names no value it took, so the data value import'sobjectsis always empty. - A job the block follows, the analytics and resource tables runs and
dhis2.task_wait, answers itstask_id,completed_atand the last fewmessagesof its notification feed. - Every read answers
duration_ms.
A read that names uids to scope itself to -- a data set, data element, org unit or program --
asks the instance whether each exists first, in one metadata lookup, and fails rejected with
dhis2.unknown_uids naming the ones it does not know, rather than answering an empty read for a
typo. require_known: false skips the lookup, for an account that may read the data but not
the metadata describing it.
| Block | Kind | Group | Summary |
|---|---|---|---|
dhis2.analytics_query |
operator | dhis2 | Run a DHIS2 analytics query. |
dhis2.analytics_run |
operator | dhis2 | Run the DHIS2 analytics tables job. |
dhis2.data_set_completion |
operator | dhis2 | Mark a DHIS2 data set complete, or reopen it, for a period and org unit. |
dhis2.data_store |
operator | dhis2 | Get, set or delete a DHIS2 data store key, or list a namespace's keys. |
dhis2.data_value |
operator | dhis2 | Get, set or delete one DHIS2 data value by data element, period and org unit. |
dhis2.data_value_set_export |
operator | dhis2 | Export a DHIS2 data value set as JSON, CSV, XML or ADX. |
dhis2.data_value_set_import |
operator | dhis2 | Import a data value set into DHIS2, as JSON, CSV, XML or ADX. |
dhis2.message |
operator | dhis2 | Send a DHIS2 message to users, user groups or org units. |
dhis2.metadata |
operator | dhis2 | Read one DHIS2 metadata collection, whole or one page of it. |
dhis2.metadata_export |
operator | dhis2 | Read several DHIS2 metadata collections, every row of each, in one request. |
dhis2.metadata_import |
operator | dhis2 | Create, update or delete DHIS2 metadata from a bundle, one object or many. |
dhis2.predictor_run |
operator | dhis2 | Run DHIS2 predictors over a date range. |
dhis2.resource_tables_run |
operator | dhis2 | Rebuild the DHIS2 resource tables, without the analytics tables. |
dhis2.sql_view |
operator | dhis2 | Run a DHIS2 SQL view by uid and read its rows. |
dhis2.system_info |
operator | dhis2 | Read a DHIS2 instance's version, build, server clock and analytics state. |
dhis2.task_wait |
operator | dhis2 | Wait on a DHIS2 background job by its job type and id. |
dhis2.tracker |
operator | dhis2 | Read DHIS2 tracker objects. |
dhis2.tracker_import |
operator | dhis2 | Create, update or delete DHIS2 tracked entities, enrollments, events and relationships. |
dhis2.validation_run |
operator | dhis2 | Run DHIS2 validation rule analysis and answer the violations. |
dhis2.data_set_complete |
sensor | dhis2 | Wait for a DHIS2 data set to be marked complete. |
Operators¶
dhis2.analytics_query¶
Run a DHIS2 analytics query.
Idempotent.
Runs one query and hands the grid on: aggregate reads /api/analytics, and event or
enrollment reads /api/analytics/{events,enrollments}/query under one program, which is why
those two modes require a program. A program that is not a DHIS2 uid fails the step before any
request is sent, so a value from a run param or a source's input stays inside the query path, and
one the instance does not know fails it with dhis2.unknown_uids unless require_known is off.
rows is the grid read by name: each row an object keyed by its header's name, so an aggregate
row reads {dx, pe, ou, value} rather than a list whose positions follow dimension. body is
the grid as DHIS2 answered it, for the metaData that names every item and the headers that
type every column. An event or enrollment query's pager comes from the grid's own
metaData.pager.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
mode |
"aggregate" or "event" or "enrollment" |
yes | Which analytics query to run: aggregate over /api/analytics, or an event or enrollment query over /api/analytics/{events,enrollments}/query. |
|
dimension |
string[] |
[] |
The DHIS2 dimension= axes, such as dx:fbfJHSPpUQD or pe:LAST_12_MONTHS. |
|
filter |
string or string[] |
[] |
The DHIS2 filter= axes, fixing a dimension the result is not broken down by: one string such as ou:ImspTQPwCqd, or a list such as [ou:ImspTQPwCqd, pe:2026Q1] that is sent as one filter= each. |
|
program |
string or null |
null |
The uid of the program an event or enrollment query reads; unused for aggregate. |
|
start_date |
string or null |
null |
The ISO start of the query window, for the query kinds that take one. | |
end_date |
string or null |
null |
The ISO end of the query window, for the query kinds that take one. | |
output_id_scheme |
string or null |
null |
The DHIS2 outputIdScheme, such as UID or NAME, applied to the answer. |
|
page |
integer or null |
null |
The 1-based page to read, for the event and enrollment queries that page. | |
page_size |
integer or null |
null |
How many rows a page holds, for the event and enrollment queries that page. | |
require_known |
boolean |
true |
Whether an event or enrollment query fails when its program is unknown to the instance, rather than answering an empty grid. One metadata lookup asks for it first. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
rows |
object[] |
yes | The grid's rows, each an object keyed by its header's name, such as dx, pe, ou and value. |
|
pager |
object or null |
null |
The page an event or enrollment query read and whether more follow; null for a grid that is not paged. | |
body |
any or null |
null |
The grid as DHIS2 answered it: headers, metaData with the names of every item, rows as lists, height and width. |
|
duration_ms |
integer |
yes | How long the query took. |
dhis2.analytics_run¶
Run the DHIS2 analytics tables job.
Not idempotent. Polls every 1m unless the step says otherwise.
Asks the instance first whether an analytics job is already running, and follows that one
instead of submitting a second when it is; join_running: false always submits, and so does a
user the instance refuses the job listing. Otherwise it submits the job to
/api/resourceTables/analytics. A job type or task id in the answer that is not one plain path
segment fails the step with dhis2.task.no_reference, before the task is polled. Either
way it then follows the task's notification feed: each
probe streams the messages new since its cursor into the run's log, and the feed's own
completion is what ends the step. A task that has written nothing fifteen minutes after
submission is taken to be gone, because DHIS2 answers a task it never had exactly the way it
answers one that has not spoken yet. A feed that is empty after it had spoken is gone at once:
an instance that restarts drops every task's notifications, and the job with them. Collecting
the result asks for the terminal notification, and a feed without one fails the step as
transient rather than answering an empty story as a success. DHIS2 offers no way to stop a
running analytics job, so a cancelled step leaves the job to finish on the instance.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
last_years |
integer or null |
null |
Limit the tables to this many years back, or leave unset to build them all. | |
skip_resource_tables |
boolean |
false |
Whether the resource tables are left as they are. | |
skip_aggregate |
boolean |
false |
Whether aggregate data analytics tables are left as they are. | |
skip_events |
boolean |
false |
Whether event analytics tables are left as they are. | |
skip_enrollment |
boolean |
false |
Whether enrollment analytics tables are left as they are. | |
skip_org_unit_ownership |
boolean |
false |
Whether the org unit ownership table is left as it is. | |
join_running |
boolean |
true |
Whether an analytics job already running on the instance is followed instead of a second one being submitted. The joined job runs with the options it was started with, not these. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
task_id |
string |
yes | The id the instance gave the job. | |
completed_at |
string or null |
null |
When the task said it was done, in the instance's own timestamp. | |
messages |
string[] |
yes | The last few notification messages, oldest first. | |
joined |
boolean |
false |
Whether the step followed a job already running rather than submitting its own. |
dhis2.data_set_completion¶
Mark a DHIS2 data set complete, or reopen it, for a period and org unit.
Idempotent.
Posts one completion registration to /api/completeDataSetRegistrations, the path every supported
version writes registrations through and the one that takes dryRun, and reads the import summary
as the instance's verdict. completed: false reopens the window rather than deleting the
registration, which is what dhis2.data_set_complete reads as a window still open. A summary whose
status is ERROR, or one that ignored the registration, fails the step with
dhis2.data_set_completion.refused and the instance's reason; an answer with no summary in it
fails with dhis2.import.no_summary. Both are rejected.
Each conflict carries the instance's object and value, its error_code, and the indexes of
the refused registrations.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
data_set |
string |
yes | The uid of the data set. | |
period |
string |
yes | An ISO period identifier, such as 202607 or 2026Q1. | |
org_unit |
string |
yes | The uid of the organisation unit. | |
attribute_option_combo |
string or null |
null |
The uid of the attribute option combo, for a data set with an attribute category combo; the default combo when unset. | |
completed |
boolean |
true |
Whether the window is marked complete; false reopens it. | |
dry_run |
boolean |
false |
Whether the instance validates the registration without writing anything. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
status |
string |
yes | The summary's own word: SUCCESS or WARNING. | |
completed |
boolean |
yes | Whether the window was marked complete, or reopened. | |
dry_run |
boolean |
yes | Whether this was a validation only, with nothing written. | |
sent |
integer |
yes | How many registrations were sent: one. | |
counts |
object |
yes | What happened to the registration: imported, updated, ignored or deleted. | |
conflicts |
object[] |
yes | Every refusal the summary names, empty when the registration was taken. |
dhis2.data_store¶
Get, set or delete a DHIS2 data store key, or list a namespace's keys.
Idempotent.
Addresses the data store, /api/dataStore, or with user_store the signed-in user's own,
/api/userDataStore. keys lists a namespace's keys as rows; get, set and delete take
one key, and a config missing it is refused at apply with dhis2.data_store.no_key, as a set
with no value is with dhis2.data_store.no_value.
Every action reads first, so the output says whether the key was there: a get of a key the
namespace does not hold answers found: false and a null value rather than failing, a
delete of one sends nothing, and a set creates the key with a POST when it was not there and
replaces it with a PUT when it was, saying which in created. The value is read as it is stored,
an object, a list or a scalar. encrypt asks the instance to store a set's value encrypted.
DHIS2 has no dry run for the data store. A namespace and a key are each one path segment, escaped,
and one holding a slash is refused.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
action |
"get" or "set" or "delete" or "keys" |
"get" |
What the step does: get reads the key, set writes value to it, creating or replacing it, delete removes it, and keys lists the namespace's keys. |
|
namespace |
string |
yes | The namespace, such as an app's own or one an integration keeps its state in. | |
key |
string or null |
null |
The key in the namespace; every action but keys needs one. |
|
value |
any |
null |
The JSON to store, for set: an object, a list, a string, a number or a boolean. |
|
encrypt |
boolean |
false |
Whether set asks the instance to store the value encrypted. |
|
user_store |
boolean |
false |
Whether the step addresses the signed-in user's own store, /api/userDataStore, rather than the shared one. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
action |
"get" or "set" or "delete" or "keys" |
yes | What the step did. | |
namespace |
string |
yes | The namespace addressed. | |
key |
string or null |
null |
The key addressed; null for keys. |
|
found |
boolean |
yes | Whether the key, or for keys the namespace, was there before the step: a get of a key that is not there answers false rather than failing, and so does a delete. |
|
value |
any |
null |
The value read, or the value written; null for delete, for keys, and for a key that was not there. |
|
rows |
string[] |
The namespace's keys, for keys; empty for every other action. |
||
created |
boolean |
false |
Whether set made a new key rather than replacing one. |
dhis2.data_value¶
Get, set or delete one DHIS2 data value by data element, period and org unit.
Not idempotent.
Addresses one cell through /api/dataValues: get reads it, set posts value (and
comment), delete removes it. The attribute option combo is named the way that endpoint names
one, as attribute_combo and attribute_options together, sent as cc and cp; the endpoint
takes no attribute option combo uid and files a value under the default combo when given one.
Half the pair is refused at apply with dhis2.data_value.half_attribute, and a set without a
value with dhis2.data_value.no_value; a run whose references resolve to either is refused the
same way before anything is sent.
A get of an empty cell is not a failure: the output says found: false. DHIS2 2.43 and later
answer that read 404, and 2.42 answers 409 with "Data value does not exist"; both are read as
absent, and any other 409 is a refusal.
A dry run never calls /api/dataValues, which accepts dryRun=true and writes the value anyway.
It sends the cell as a one-value /api/dataValueSets import with dryRun=true instead, with
importStrategy=DELETE for a delete, and an attribute option combo is resolved to its uid by
reading the attribute combo's option combos first. A rehearsal the instance would refuse fails the
step with dhis2.data_value.refused and its reason.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
action |
"get" or "set" or "delete" |
"get" |
What the step does: get reads the value, set writes value, delete removes it. |
|
data_element |
string |
yes | The uid of the data element. | |
period |
string |
yes | An ISO period identifier, such as 202607 or 2026Q1. | |
org_unit |
string |
yes | The uid of the organisation unit. | |
category_option_combo |
string or null |
null |
The uid of the category option combo, the disaggregation; the default combo when unset. | |
attribute_combo |
string or null |
null |
The uid of the attribute category combo, given together with attribute_options; the default attribute option combo when both are unset. |
|
attribute_options |
string[] |
[] |
The uids of the attribute category options that, with attribute_combo, name the attribute option combo. |
|
value |
string or null |
null |
The value to write, always a string on the wire whatever the value type; set needs one. |
|
comment |
string or null |
null |
A comment to store with the value, for set. |
|
dry_run |
boolean |
false |
Whether a set or delete is only validated, with nothing written. It is sent as a one-value /api/dataValueSets import with dryRun=true, because /api/dataValues accepts dryRun and writes the value anyway. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
action |
"get" or "set" or "delete" |
yes | What the step did. | |
data_element |
string |
yes | The uid of the data element. | |
period |
string |
yes | The ISO period. | |
org_unit |
string |
yes | The uid of the organisation unit. | |
category_option_combo |
string or null |
null |
The uid of the category option combo, when one was named. | |
attribute_option_combo |
string or null |
null |
The uid of the attribute option combo a dry run resolved, when one was named. | |
value |
string or null |
null |
The value read or written; null when a read found none, and for a delete. | |
found |
boolean |
yes | Whether the value exists: for get whether one is stored, otherwise whether the write was taken. |
|
dry_run |
boolean |
yes | Whether this was a validation only, with nothing written. |
dhis2.data_value_set_export¶
Export a DHIS2 data value set as JSON, CSV, XML or ADX.
Idempotent.
Reads what /api/dataValueSets is asked for and answers with the parsed document as its body,
which a dhis2.data_value_set_import takes whole as data_values: ${steps.<step>.output.body}.
A run that has to leave the export behind as a file hands that body to storage.write, which is
the only block that puts a value into storage.
Each selector takes one uid or a list. DHIS2 needs one of each kind, and a config missing one is
refused before any request: what to read (data_set, data_element or data_element_group),
where (org_unit or org_unit_group, with children for the descendants), and when (period,
start_date with end_date, last_updated, or last_updated_duration). An incremental sync
reads last_updated from the previous run's start, or last_updated_duration: 1d on a daily
schedule. include_deleted adds the values deleted since, marked deleted, and the id schemes
write the document's identifiers as codes, names or an attribute's values instead of uids.
Every named data set, data element, group and org unit is looked up first, in one request: a uid
the instance does not know fails the step with dhis2.unknown_uids instead of exporting an
empty set for it. require_known: false skips the lookup.
An answer with no body at all fails the step as rejected with dhis2.export.empty_answer:
DHIS2 answers 200 and nothing else for an org unit outside the account's data scope, where an
export that found no values still answers with a dataValues list. An export of one data set
whose answer names neither the data set nor a dataValues list is refused the same way; DHIS2
2.42 leaves the data set out of a last_updated read, values or none, so a dataValues list
alone is an answer.
Every value in the body carries its own period, orgUnit and attributeOptionCombo. DHIS2
2.43 writes a field once on the set when every value shares it, and a one-unit export's values
then carry no org unit at all, where 2.42 repeats them on every value; the block copies what the
set holds down onto each value that lacks it, never over a value's own, so a step reading
dataValues[].period reads the same from either version.
With children, the body leaves out the document-level orgUnit DHIS2 echoes back. An import
applies that field to every value in place of the value's own, so a body that kept it would
write each descendant's values onto the org unit the export was asked for.
format picks the form: json, the default, parses the set into body; csv, xml and adx
are text, streamed from /api/dataValueSets.csv, /api/dataValueSets.xml, or
/api/dataValueSets with Accept: application/adx+xml, into the run's storage as it arrives.
The output then carries uri, where the whole export was written and what an import's
data_values_uri reads, and text, its head cut at the instance's inline capture size, with
truncated saying whether it was cut and content_bytes its size; body is null. Every
selector and id scheme applies in every form. An empty text answer is the same
dhis2.export.empty_answer as an empty JSON one.
| DHIS2 | JSON | CSV | XML | ADX |
|---|---|---|---|---|
| 2.41 | export, import | export, import | export, import | export, import |
| 2.42 | export, import | export, import | export, import | export, import |
| 2.43 | export, import | export, import | export, import | import |
| 2.44 | export, import | export, import | export, import | import |
DHIS2 2.43 and 2.44 answer an ADX export with JSON, so an adx export from them is refused with
dhis2.export.format_unsupported before it is asked, and an ADX answer that is JSON is refused
the same way. Their XML export writes the set's period as an ISO interval, 2025-07-01/P1M,
which their own XML import refuses with a 500; CSV and JSON round-trip on every version.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
data_set |
string or string[] or null |
null |
The uid of a data set to export, or a list of them. | |
data_element |
string or string[] or null |
null |
The uid of a data element to export, or a list of them. | |
data_element_group |
string or string[] or null |
null |
The uid of a data element group whose members are exported, or a list of them. | |
period |
string or string[] or null |
null |
An ISO period identifier such as 2026Q1, or a list of them. | |
start_date |
string or null |
null |
The ISO start of a date range read in place of periods, taken with end_date. |
|
end_date |
string or null |
null |
The ISO end of a date range read in place of periods, taken with start_date. |
|
last_updated |
string or null |
null |
Read only values changed at or after this ISO date or instant, for an incremental sync. | |
last_updated_duration |
string (humane-duration) or null |
null |
Read only values changed within this long before now, such as 1d or 2h. |
|
org_unit |
string or string[] or null |
null |
The uid of an organisation unit to export for, or a list of them. | |
org_unit_group |
string or string[] or null |
null |
The uid of an organisation unit group whose members are exported for, or a list of them. | |
children |
boolean |
false |
Whether the org units' descendants are included. The exported document then carries no document-level orgUnit, and each value keeps its own. |
|
include_deleted |
boolean |
false |
Whether values deleted on the instance are exported too, each marked deleted. |
|
id_scheme |
string or null |
null |
How every identifier in the document is written: UID, CODE, NAME, ID or ATTRIBUTE:<uid>; the instance's own default, UID, when unset. |
|
data_element_id_scheme |
string or null |
null |
How data elements are written, in place of id_scheme. |
|
org_unit_id_scheme |
string or null |
null |
How org units are written, in place of id_scheme. |
|
category_option_combo_id_scheme |
string or null |
null |
How category option combos are written, in place of id_scheme. |
|
format |
"json" or "csv" or "xml" or "adx" |
"json" |
The form the set is exported in: json, parsed into body; or csv, xml or adx, written whole to storage at uri with its head inlined as text. ADX is exported by 2.41 and 2.42 only. |
|
require_known |
boolean |
true |
Whether the step fails when a named data set, data element, group or org unit is unknown to the instance, rather than answering an empty set for it. One metadata lookup asks for every named uid before the export. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
format |
"json" or "csv" or "xml" or "adx" |
"json" |
The form the set was exported in. | |
body |
any or null |
null |
The exported data value set, for json: the document a dhis2.data_value_set_import takes whole as its data_values. Every value carries its own period, org unit and attribute option combo, whichever version answered. Null for every other form. |
|
text |
string or null |
null |
The head of the exported text, for csv, xml and adx, cut at the instance's inline capture size; null for json. |
|
uri |
string or null |
null |
Where the whole exported text was written, for csv, xml and adx; never cut, and what an import's data_values_uri takes. Null for json. |
|
content_bytes |
integer or null |
null |
How large the exported text is, inlined or not; null for json. |
|
truncated |
boolean |
false |
Whether text is short of the export. Only the inline copy is ever cut. |
|
duration_ms |
integer |
yes | How long the export took. |
dhis2.data_value_set_import¶
Import a data value set into DHIS2, as JSON, CSV, XML or ADX.
Not idempotent.
Sends the document in data_values, written in the step or referenced from an upstream
output, or the one stored at data_values_uri. A document that is not an object
with a dataValues list fails rejected with dhis2.import.no_data_values before anything is
sent: the usual cause is an export's whole output, ${steps.export.output}, passed where its
document, ${steps.export.output.body}, was meant. An empty dataValues list is sent, and the
output's sent: 0 says there was nothing to import; require_values: true fails the step with
dhis2.import.no_values_taken when the instance took no value at all.
The block reads the import summary as the instance's verdict: a 409 carrying a summary is that
verdict too, not a transport failure. A summary whose status is ERROR fails the step with the
first conflicts named, and so does a WARNING with ignored values under atomic_mode: ALL.
DHIS2 does not honour ALL as the rollback it describes: on every supported major the good
values are committed beside the conflicts, so that failure names how many values landed. An
envelope whose own status is ERROR fails the same way, whatever its summary says. A 200 without
an import summary in it fails the step too, since nothing then says the import took, and so does a
summary whose status is any word but SUCCESS or WARNING. A summary is a response with
responseType: ImportSummary, an importCount object, or the counts inline. A 409 with none of
those is an ordinary refusal, dhis2.answered. Every one of these failures is rejected, so the same document is not retried against the same
instance.
Each conflict carries the instance's object and value, its error_code, and the indexes
of the refused values in the document that was sent. DHIS2 2.43 names no object, so there
the indexes are what says which value it was, and a failure names it as value #1.
A dry run sends the document without its completeDate, and says so in the log. DHIS2 2.41 and
2.42 register the data set complete under dryRun=true, and a rehearsal must persist nothing.
format says what the document is written in, and it is sent in that media type to
/api/dataValueSets: json takes the object above; csv, xml and adx take the document's
text in data_values, and an object or a list there fails rejected with
dhis2.import.not_text. data_values_uri names a storage object to send in place of
data_values, such as an export's uri, and naming both is refused with
dhis2.import.two_sources. sent counts a CSV's rows past its header, and the dataValue
elements of XML and ADX. A dry run of XML or ADX leaves a completeDate attribute out the way
a JSON dry run leaves the field out.
id_scheme, data_element_id_scheme, org_unit_id_scheme and
category_option_combo_id_scheme say how the document names things: UID, CODE, NAME, ID
or ATTRIBUTE:<uid>. ADX is written in codes, which 2.41 and 2.42 assume and 2.43 and later do
not, so an adx import is sent with idScheme=CODE unless id_scheme says otherwise. DHIS2 2.41
to 2.44 import all four forms.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
data_values |
any |
null |
The data value set to send, written in the step or referenced from one. For json an object with a dataValues list: an export's document is ${steps.<step>.output.body}, and a document with no dataValues list fails the step before anything is sent. For csv, xml and adx the document's text, such as an export's ${steps.<step>.output.text} when it was not truncated. |
|
data_values_uri |
string or null |
null |
A storage URI holding the document to send, read in place of data_values: an export's ${steps.<step>.output.uri}, or a file a storage.write left. |
|
format |
"json" or "csv" or "xml" or "adx" |
"json" |
The form the document is written in: json, csv, xml or adx. DHIS2 2.41 to 2.44 import all four. |
|
id_scheme |
string or null |
null |
How every identifier in the document is written: UID, CODE, NAME, ID or ATTRIBUTE:<uid>; UID when unset, except for adx, which is sent as CODE unless this says otherwise. |
|
data_element_id_scheme |
string or null |
null |
How data elements are written, in place of id_scheme. |
|
org_unit_id_scheme |
string or null |
null |
How org units are written, in place of id_scheme. |
|
category_option_combo_id_scheme |
string or null |
null |
How category option combos are written, in place of id_scheme. |
|
dry_run |
boolean |
false |
Whether the instance validates the import without writing anything. A completeDate in the document is left out of a dry run: DHIS2 2.41 and 2.42 register the data set complete even under dryRun, and a rehearsal must persist nothing. |
|
import_strategy |
"CREATE" or "UPDATE" or "CREATE_AND_UPDATE" or "DELETE" |
"CREATE_AND_UPDATE" |
What the import may do to existing values: CREATE, UPDATE, CREATE_AND_UPDATE, or DELETE. | |
atomic_mode |
"ALL" or "NONE" |
"ALL" |
ALL asks the instance to refuse the whole import on any conflict; NONE takes what it can. DHIS2 does not always honour ALL and may commit the good values beside the conflicts, so a failure under ALL names what landed. | |
require_values |
boolean |
false |
Whether the step fails when the instance took no value at all: none imported, updated or deleted. Off, an empty dataValues list is sent and answers zero counts. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
status |
string |
yes | The summary's own word: SUCCESS or WARNING. | |
dry_run |
boolean |
yes | Whether this was a validation only, with nothing written. | |
sent |
integer |
yes | How many values the document held; zero says nothing was there to import. | |
counts |
object |
yes | What happened to the values: imported, updated, ignored and deleted. | |
objects |
any[] |
yes | Every value the summary names on its own, always empty: DHIS2's data value summary counts values and names only the refused ones, in conflicts. |
|
conflicts |
object[] |
yes | Every value the instance refused, empty when the import was clean. |
Each conflict is an object of object and value in the instance's own words, its error_code, and the indexes of the refused values.
dhis2.message¶
Send a DHIS2 message to users, user groups or org units.
Not idempotent.
Starts one message conversation through POST /api/messageConversations, the same inbox the
DHIS2 web apps read. DHIS2 also sends it as email to every recipient with an email address
where the instance has SMTP configured; whether the email went out is the instance's to know,
and nothing in the answer says.
A user group reaches its members and an organisation unit the users assigned to it, so one message can reach many more people than it names. The output counts what was named, not who the instance expanded it to.
At least one recipient is required, in any of the three lists. A step naming none is refused
at apply with dhis2.message.no_recipient, and so is a run whose references resolve to none.
Every recipient is a DHIS2 uid. A 400 or a 409 from the instance -- such as a send whose
recipients name no one it knows -- is rejected.
DHIS2 answers a send with the new conversation's uid on the Location header only, so the
block reads the conversation back to report it. A send the instance took without saying
where is rejected, never retried, because a retry would send the message twice.
If DHIS2 accepts the message but the fetch-back fails, a retry can send it twice, because
dhis2w's messaging.send posts and then reads back.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
subject |
string |
yes | The subject line, up to 255 characters. | |
text |
string |
yes | The body of the message, which may be long and may be built from references. | |
users |
string[] |
[] |
The uids of the users the message goes to. | |
user_groups |
string[] |
[] |
The uids of the user groups whose members the message goes to. | |
org_units |
string[] |
[] |
The uids of the organisation units whose assigned users the message goes to. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
conversation_id |
string |
yes | The uid of the message conversation the instance created. | |
user_count |
integer |
yes | How many users the message named. | |
user_group_count |
integer |
yes | How many user groups the message named. | |
org_unit_count |
integer |
yes | How many organisation units the message named. |
dhis2.metadata¶
Read one DHIS2 metadata collection, whole or one page of it.
Idempotent.
Reads one collection through the version-bound generic accessor, so resource is the
collection name as it appears in the API path and a name the instance's version does not
publish is rejected rather than retried. paging is off by default: a metadata read wants
the whole collection, not its first page.
The rows come back under rows, and a paged read's pager says where it stands. It is also
how a collection is counted: paging: true and page_size: 1 send one row, and the output's
pager.total is how many there are. Several collections read whole are one
dhis2.metadata_export step instead.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
resource |
string |
yes | The DHIS2 collection name, as it appears in the API path: organisationUnits, dataElements, dataSets, indicators, programs, optionSets, trackedEntityTypes, and the rest the version-bound client knows. |
|
fields |
string or string[] or null |
null |
The DHIS2 fields= selector, as one string such as id,name,valueType or a list such as [id, name, valueType] that is sent comma-joined; the instance's own default when unset. Inside a YAML flow list a nested selector such as parent[id,code] must be quoted, as in [id, "parent[id,code]"], because YAML refuses an unquoted bracket or comma in a flow item. |
|
filter |
string or string[] or null |
null |
One or more DHIS2 filter= expressions: one string such as level:eq:2, or a list such as [level:eq:2, name:like:Bo] that is sent as one filter= each, ANDed unless the resource is told otherwise. |
|
paging |
boolean |
false |
Whether the read is paged. Off by default: a metadata read wants the whole collection, not the first page of it. | |
order |
string or string[] or null |
null |
The DHIS2 order= terms: one string such as name:asc, or a list such as [level:asc, name:asc] that is sent comma-joined, the first term sorting first. |
|
page |
integer or null |
null |
The 1-based page to read, when paging is on. |
|
page_size |
integer or null |
null |
How many rows a page holds, when paging is on. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
rows |
any[] |
yes | The collection's rows, each with the fields fields selected. |
|
pager |
object or null |
null |
The page read, the page size, the collection's total, and whether more pages follow; null when the read is not paged and so answered every row. | |
duration_ms |
integer |
yes | How long the read took. |
The instance's own version and system information is not a metadata collection, so it is read
with dhis2.system_info rather than with this block.
dhis2.metadata_export¶
Read several DHIS2 metadata collections, every row of each, in one request.
Idempotent.
Reads every collection resources names in one GET /api/metadata, and answers with each under
its own name in collections and its row count in totals. Each name is checked against the
version-bound client first, so a name the instance's version does not publish is rejected
before any export is sent. fields, filter and order are shared by every collection; a
collection written as a mapping key may name its own, which replace the shared ones for it alone.
Every term is sent scoped to its collection, as <resource>:fields, <resource>:filter and
<resource>:order.
/api/metadata has no pager: it answers with every row that matches. To count a collection,
read it with dhis2.metadata, paging: true and page_size: 1, and take
pager.total.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
resources |
string[] or object |
yes | The DHIS2 collection names to read, as they appear in the API path: a list such as [dataSets, programs] that each take the shared terms, or a mapping from a name to its own fields, filter and order, where a term a collection leaves unset falls back to the shared one and {} takes them all. |
|
fields |
string or string[] or null |
null |
The fields= selector every collection is read with unless it names its own: one string such as id,name or a list sent comma-joined; DHIS2's own :owner when unset. |
|
filter |
string or string[] or null |
null |
The filter= expressions every collection is narrowed by unless it names its own: one string such as name:like:ANC or a list sent as one filter each and ANDed. |
|
order |
string or string[] or null |
null |
The order= terms every collection is sorted by unless it names its own: one string such as name:asc or a list sent comma-joined. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
collections |
object of any[] |
yes | Every collection asked for, keyed by its name, holding the rows the instance answered with; an empty list for a collection with no row that matched. | |
totals |
object of integer |
yes | How many rows each collection holds in collections, keyed by its name. |
|
duration_ms |
integer |
yes | How long the export took. |
dhis2.metadata_import¶
Create, update or delete DHIS2 metadata from a bundle, one object or many.
Not idempotent.
Posts one bundle to /api/metadata: an object keyed by collection name, each holding the
objects to write. It is the shape dhis2.metadata_export answers under collections, and DHIS2's
own export, so an export's collections is a bundle as it stands. One object is a bundle of one:
{dataElements: [{...}]} creates a data element, the same bundle holding only its id deletes it
under import_strategy: DELETE, and import_strategy: UPDATE with merge_mode: MERGE changes the
fields it names and keeps the rest. There is no separate single-object block, because the
per-object endpoints have no dry run and answer a different report.
A dry run is sent as importMode=VALIDATE, never dryRun: the metadata importer accepts
dryRun=true without a word and commits the bundle. atomic_mode takes ALL or NONE only,
since the importer reads the tracker's OBJECT, or any other word, as ALL. The report is asked
for in full, so objects names every object with its uid, including one the instance generated.
The report is read whether it came on 200 or on 409. A report whose status is ERROR fails the
step with dhis2.metadata_import.refused, naming the first refused objects, unless
fail_on_error is off, when the step succeeds and conflicts carries them. A bundle that is not an
object is refused with dhis2.metadata_import.not_a_bundle before anything is sent, and an answer
with no report in it fails with dhis2.metadata_import.no_report. Every one of these is
rejected.
counts and each entry of by_class are the pack's import counts, with DHIS2's created
answered as imported. Each object names its object_class, uid and index; each conflict
adds the instance's error_code, its words as value, and the property it is about.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
metadata |
any |
yes | The metadata bundle to send: an object keyed by collection name, such as {dataElements: [...], dataSets: [...]}, written in the step or referenced from an upstream output. |
|
dry_run |
boolean |
false |
Whether the instance validates the bundle without writing anything, sent as importMode=VALIDATE: DHIS2's metadata importer ignores dryRun and commits. |
|
import_strategy |
"CREATE_AND_UPDATE" or "CREATE" or "UPDATE" or "DELETE" |
"CREATE_AND_UPDATE" |
What the import may do to existing objects: CREATE_AND_UPDATE, CREATE, UPDATE, or DELETE. | |
atomic_mode |
"ALL" or "NONE" |
"ALL" |
ALL refuses the whole bundle when any object is refused; NONE writes what it can. | |
identifier |
"UID" or "CODE" or "AUTO" |
"UID" |
Which property objects and references are matched by: UID, CODE, or AUTO for either. | |
merge_mode |
"REPLACE" or "MERGE" or null |
null |
How an update meets the stored object: REPLACE overwrites every field, MERGE keeps the fields the bundle leaves out; the instance's own default, REPLACE, when unset. | |
skip_sharing |
boolean |
false |
Whether the sharing settings in the bundle are left out of the import. | |
fail_on_error |
boolean |
true |
Whether a report whose status is ERROR fails the step; off, the step succeeds and the output carries the errors. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
status |
string |
yes | The report's own word: OK, WARNING, or ERROR when fail_on_error is off. |
|
dry_run |
boolean |
yes | Whether this was a validation only, with nothing written. | |
sent |
integer |
yes | How many objects the bundle held, across its collections. | |
counts |
object |
yes | What happened to the objects: imported (DHIS2's created), updated, ignored and deleted. | |
by_class |
object of object |
yes | The same counts for each class of object in the bundle, keyed by class, such as DataElement. | |
objects |
object[] |
yes | Every object the report names, with its uid. | |
conflicts |
object[] |
yes | Every object the report refused, empty when the import was clean. |
dhis2.predictor_run¶
Run DHIS2 predictors over a date range.
Idempotent.
Runs one predictor through /api/predictors/{uid}/run, one predictor_group through
/api/predictorGroups/{uid}/run, or with neither every predictor on the instance through
/api/predictors/run, for start_date to end_date; naming both is refused with
dhis2.predictor.both_targets. The run is one request that DHIS2 holds open until the values are
written, and predictions is the count its answer gives, with the summary's inserted,
updated, deleted and unchanged where the version reports them. DHIS2 has no dry run for
predictors, so every example that runs one names no group by default.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
start_date |
string |
yes | The ISO date the range starts on, such as 2026-01-01. | |
end_date |
string |
yes | The ISO date the range ends on, such as 2026-03-31. | |
predictor |
string or null |
null |
The uid of one predictor to run. | |
predictor_group |
string or null |
null |
The uid of a predictor group whose members run. With neither this nor predictor, every predictor on the instance runs. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
predictions |
integer |
yes | How many values the run predicted, as the instance counted them. | |
inserted |
integer or null |
null |
How many predicted values were new, where the instance reported it. | |
updated |
integer or null |
null |
How many replaced a value predicted before, where the instance reported it. | |
deleted |
integer or null |
null |
How many earlier predictions were removed, where the instance reported it. | |
unchanged |
integer or null |
null |
How many matched what was already there, where the instance reported it. | |
message |
string or null |
null |
What the instance said, in its own words. |
dhis2.resource_tables_run¶
Rebuild the DHIS2 resource tables, without the analytics tables.
Not idempotent. Polls every 30s unless the step says otherwise.
Submits POST /api/resourceTables, the resource tables on their own without the analytics
tables, and follows the RESOURCE_TABLE job exactly as dhis2.analytics_run follows its own: a
job already running is joined unless join_running is off, each probe streams the new
notifications into the run's log, and a task silent for fifteen minutes, or whose feed empties
after it had spoken, is gone. A job that ends at level ERROR fails the step with its last
message. DHIS2 offers no way to stop the job, so a cancelled step leaves it to finish.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
join_running |
boolean |
true |
Whether a resource tables job already running on the instance is followed instead of a second one being submitted. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
task_id |
string |
yes | The id the instance gave the job. | |
completed_at |
string or null |
null |
When the task said it was done, in the instance's own timestamp. | |
messages |
string[] |
yes | The last few notification messages, oldest first. | |
joined |
boolean |
false |
Whether the step followed a job already running rather than submitting its own. |
dhis2.sql_view¶
Run a DHIS2 SQL view by uid and read its rows.
Idempotent.
Runs GET /api/sqlViews/{uid}/data.json for a stored view and answers its grid as rows, each
an object keyed by the result's column names, with columns beside them. variables fill a
QUERY view's ${name} placeholders, each sent as var=name:value, and criteria narrow a
VIEW or MATERIALIZED_VIEW by column, each sent as criteria=column:value. The block sends
no SQL of its own.
DHIS2 pages a view's result at 50 rows unless told otherwise, so an unpaged step asks for every
row with paging=false; paging: true reads one page of page_size and answers a pager.
A uid the instance holds no view by fails rejected.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
sql_view |
string |
yes | The uid of the SQL view to run. | |
variables |
object |
Values for a QUERY view's ${name} placeholders, keyed by name. DHIS2 keeps only letters and digits of each value, so a wildcard belongs in the view's SQL. |
||
criteria |
object |
Column values a VIEW or MATERIALIZED_VIEW result is narrowed to, keyed by column, every one of them matched. |
||
paging |
boolean |
false |
Whether the read is paged. Off by default: DHIS2 answers a view's first 50 rows unless told otherwise, and a view is read for all of its rows. | |
page |
integer or null |
null |
The 1-based page to read, when paging is on. |
|
page_size |
integer or null |
null |
How many rows a page holds, when paging is on. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
rows |
object[] |
yes | The view's rows, each an object keyed by column name. | |
columns |
object[] |
yes | The result's columns, in the order the view selects them. | |
title |
string or null |
null |
The view's name, as the result carries it. | |
pager |
object or null |
null |
The page read, the page size, the total and whether more pages follow; null when the read is not paged and so answered every row. | |
duration_ms |
integer |
yes | How long the read took. |
dhis2.system_info¶
Read a DHIS2 instance's version, build, server clock and analytics state.
Idempotent.
Reads /api/system/info through the connection, so a base_url that redirects is followed the
way the connection allows it and no follow_redirects_with_auth is needed. The keys a report
reads most are lifted into named fields; every other key, and a named one that did not hold a
string, is carried as the instance wrote it under other.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
version |
string or null |
null |
The DHIS2 version, such as 2.42.1. |
|
revision |
string or null |
null |
The source revision the running build was made from. | |
build_time |
string or null |
null |
When the running build was made, as the instance writes it. | |
system_id |
string or null |
null |
The instance's own system identifier. | |
system_name |
string or null |
null |
The name the instance is configured with, its application title. | |
instance_base_url |
string or null |
null |
The base URL the instance believes it is served at. | |
server_date |
string or null |
null |
The instance's clock at the moment it answered. | |
server_time_zone_id |
string or null |
null |
The time zone the server runs in, such as Etc/UTC. |
|
calendar |
string or null |
null |
The calendar the instance keeps its periods in, such as iso8601 or ethiopian. |
|
date_format |
string or null |
null |
The date format the instance shows dates in, such as yyyy-mm-dd. |
|
last_analytics_table_success |
string or null |
null |
When the analytics tables were last generated successfully. | |
last_analytics_table_runtime |
string or null |
null |
How long that last successful analytics table generation took, as the instance words it. | |
interval_since_last_analytics_table_success |
string or null |
null |
How long ago that was, as the instance words it. | |
other |
object |
Every other key of the answer, as the instance wrote it: the database, the Java runtime, the memory and processor counts, and any of the named keys that did not hold a string. | ||
duration_ms |
integer |
yes | How long the read took. |
dhis2.task_wait¶
Wait on a DHIS2 background job by its job type and id.
Idempotent. Polls every 10s unless the step says otherwise.
Follows any DHIS2 background job by the job_type it is filed under and the task_id its
submission answered with, through /api/system/tasks/{job type}/{id}, the same feed
dhis2.analytics_run reads: nothing is sent at execute, each probe streams the notifications new
since the last into the run's log, and the job's terminal notification settles the step. A job
that ends at level ERROR fails the step with its last message, a task the instance answers 404
for is gone, and so is one whose feed stays empty for fifteen minutes or empties after it had
spoken. Both halves are held to one plain path segment at validation. Waiting on a job is not
owning it, so a cancelled step leaves the job running.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
job_type |
string |
yes | The job type the task is filed under, such as DATAVALUE_IMPORT, METADATA_IMPORT, ANALYTICS_TABLE, RESOURCE_TABLE, PREDICTOR or DATA_INTEGRITY. |
|
task_id |
string |
yes | The id the instance gave the job, the response.id its submission answered with. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
task_id |
string |
yes | The id of the job that was followed. | |
job_type |
string |
yes | The job type it is filed under. | |
completed_at |
string or null |
null |
When the task said it was done, in the instance's own timestamp. | |
messages |
string[] |
yes | The last few notification messages, oldest first. |
dhis2.tracker¶
Read DHIS2 tracker objects.
Idempotent.
Reads one /api/tracker collection, scoped by program, organisation unit and ou_mode, and
narrowed by status, updated_after and filter where the collection has them. The rows come
back under rows, whatever key the instance's version filed them under.
By default the read is one page, DHIS2's first 50 rows unless page and page_size say
otherwise, and pager.more says whether rows match past it: a step that reads one page of a
larger collection is told so rather than handed the first 50 as if they were all. total: true
asks the instance to count them too, which fills pager.total and pager.page_count.
all_pages: true reads every page, from the first, and answers them as one list. It is bounded
three ways, by max_rows, max_pages and max_total (the rows' size as JSON), and reaching any
of them fails the step rejected with dhis2.tracker.cap_reached rather than answering the part
read so far. A named program or org unit the instance does not know fails the step with
dhis2.unknown_uids unless require_known is off.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
kind |
"trackedEntities" or "enrollments" or "events" |
yes | The tracker collection to read: trackedEntities, enrollments, or events. |
|
program |
string or null |
null |
The uid of the program to scope the read to. | |
org_unit |
string or null |
null |
The uid of the organisation unit to read within. | |
ou_mode |
"SELECTED" or "CHILDREN" or "DESCENDANTS" or "ACCESSIBLE" or "CAPTURE" or "ALL" or null |
null |
How the org unit is interpreted: SELECTED, CHILDREN, DESCENDANTS, ACCESSIBLE, CAPTURE, or ALL. |
|
fields |
string or string[] or null |
null |
The DHIS2 fields= selector, as one string such as event,status or a list such as [event, status] that is sent comma-joined; the instance's own default when unset. Inside a YAML flow list a nested selector such as dataValues[dataElement,value] must be quoted, as in [event, "dataValues[dataElement,value]"], because YAML refuses an unquoted bracket or comma in a flow item. |
|
filter |
string or string[] or null |
null |
One or more DHIS2 filter= expressions on the collection's attributes: one string such as w75KJ2mc4zz:like:Anna, or a list such as [w75KJ2mc4zz:like:Anna, zDhUuAYrxNC:like:Kelly] that is sent as one filter= each. Tracked entities and events take one; the enrollments collection has no attribute filter of its own, so a filter given for it rides through as a plain query parameter the instance may ignore. |
|
status |
string or null |
null |
The status to read, where the collection has one: an enrollment or event status. |
|
updated_after |
string or null |
null |
Read only rows changed at or after this ISO instant. | |
page |
integer or null |
null |
The 1-based page to read; the first when unset. The output's pager.more says whether more pages follow it. |
|
page_size |
integer or null |
null |
How many rows a page holds: the instance's own default, 50, for one page, and 500 when every page is read. | |
all_pages |
boolean |
false |
Whether every page is read, from the first until the instance has no more, and answered as one list. The read is bounded by max_rows, max_pages and max_total, and fails rather than answering part of the collection when one is reached. |
|
total |
boolean |
false |
Whether the instance counts every matching row (totalPages=true), so that pager.total and pager.page_count are known. Counting costs the instance a query of its own. |
|
max_rows |
integer |
100000 |
The most rows reading every page may gather before the step fails. | |
max_pages |
integer |
1000 |
The most pages reading every page may request before the step fails. | |
max_total |
string or integer |
"256mb" |
The most the gathered rows may come to, as JSON, before reading every page fails. | |
require_known |
boolean |
true |
Whether the step fails when the named program or org unit is unknown to the instance, rather than answering no rows for it. One metadata lookup asks for both before the read. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
rows |
any[] |
yes | The tracked entities, enrollments or events read, every page's in order when every page was read. | |
pager |
object |
yes | The page the rows came from, the page size, the totals when counted, and whether more pages follow. | |
duration_ms |
integer |
yes | How long the read took. |
dhis2.tracker_import¶
Create, update or delete DHIS2 tracked entities, enrollments, events and relationships.
Not idempotent. Polls every 10s unless the step says otherwise.
Posts one bundle of trackedEntities, enrollments, events and relationships to
/api/tracker. By default the instance runs it as a job, as DHIS2 2.41 and later do on their own,
and the step hands the job to the engine rather than holding a worker: each probe reads
/api/tracker/jobs/{id}, a notification marked complete ends the wait, and the finished job's
report is read from /api/tracker/jobs/{id}/report. A job the instance answers 404 for is gone,
and so is one that has written nothing fifteen minutes after submission. A job whose final
notification is an ERROR, as it is when the report refused an object, is finished too: its
report is read and says why, and a job that ended in error with no report to read fails with
dhis2.tracker_import.job_failed and the job's own words. DHIS2 offers no way to stop a running import, so
cancelling the step leaves it to finish. async_mode: false holds one request open and reads the
report it answers with.
A dry run is sent as importMode=VALIDATE. The report is asked for in full and read whether it
came on 200 or on 409. A report whose status is ERROR fails the step with
dhis2.tracker_import.refused, naming the first refused objects, unless fail_on_error is off. A
bundle that is not an object is refused with dhis2.tracker_import.not_a_bundle, a job answer
without a plain job id with dhis2.tracker_import.no_job, and an answer with no report in it with
dhis2.tracker_import.no_report, which is transient when the finished job's report is not there
yet and rejected otherwise.
counts and each entry of by_tracker_type are the pack's import counts, with DHIS2's created
answered as imported; by_tracker_type is keyed by DHIS2's own names: TRACKED_ENTITY,
ENROLLMENT, EVENT and RELATIONSHIP. Each object names its tracker_type, uid and
index; each conflict and warning adds the instance's error_code and its words as value.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
tracker |
any |
yes | The tracker bundle to send: an object of trackedEntities, enrollments, events and relationships lists, written in the step or referenced from an upstream output. |
|
dry_run |
boolean |
false |
Whether the instance validates the bundle without writing anything, sent as importMode=VALIDATE. |
|
import_strategy |
"CREATE_AND_UPDATE" or "CREATE" or "UPDATE" or "DELETE" |
"CREATE_AND_UPDATE" |
What the import may do to existing objects: CREATE_AND_UPDATE, CREATE, UPDATE, or DELETE. | |
atomic_mode |
"ALL" or "OBJECT" |
"ALL" |
ALL refuses the whole bundle when any object is refused; OBJECT writes every object that passes on its own. | |
async_mode |
boolean |
true |
Whether the instance runs the import as a job the engine follows, as DHIS2 does by default; off, one request is held open until the report is in. | |
fail_on_error |
boolean |
true |
Whether a report whose status is ERROR fails the step; off, the step succeeds and the output carries the errors. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
status |
string |
yes | The report's own word: OK, WARNING, or ERROR when fail_on_error is off. |
|
dry_run |
boolean |
yes | Whether this was a validation only, with nothing written. | |
job_id |
string or null |
null |
The id of the job the instance ran the import as, when it ran as one. | |
sent |
integer |
yes | How many objects the bundle held, across its four lists. | |
counts |
object |
yes | What happened to the objects: imported (DHIS2's created), updated, ignored and deleted. | |
by_tracker_type |
object of object |
yes | The same counts for each tracker type in the bundle, such as TRACKED_ENTITY or EVENT. | |
objects |
object[] |
yes | Every object the report names, with its uid. | |
conflicts |
object[] |
yes | Every error the validation report names, empty when the import was clean. | |
warnings |
object[] |
yes | Every warning the validation report names. |
dhis2.validation_run¶
Run DHIS2 validation rule analysis and answer the violations.
Idempotent.
Runs POST /api/dataAnalysis/validationRules over org_unit and every unit below it, for
start_date to end_date, every rule or one validation_rule_group, and answers each
violation: the rule, the org unit, the period, the attribute option combo, both sides and the
operator. DHIS2 runs the analysis in the foreground and answers in that one request, on every
supported version; there is no job to follow for it. max_results caps the answer.
persist and notification are the analysis's two writes, storing each violation under
/api/validationResults and sending the rules' notifications, and both are off by default, so
the analysis is a read. fail_on_violations: true fails the step rejected with
dhis2.validation.violated, naming the first violations, so a later step runs only on data
that holds.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
org_unit |
string |
yes | The uid of the org unit the analysis covers, with every unit below it. | |
start_date |
string |
yes | The ISO date the range starts on, such as 2026-01-01. | |
end_date |
string |
yes | The ISO date the range ends on, such as 2026-03-31. | |
validation_rule_group |
string or null |
null |
The uid of a validation rule group to evaluate alone; every rule when unset. | |
max_results |
integer or null |
null |
The most violations the instance answers with; its own cap, 500, when unset. | |
persist |
boolean |
false |
Whether the instance also stores each violation as a validation result, a write to /api/validationResults. Off, the analysis writes nothing. |
|
notification |
boolean |
false |
Whether the instance also sends the notifications the violated rules are set up with. | |
fail_on_violations |
boolean |
false |
Whether the step fails when any rule is violated, so a later step runs only on data that holds. Off, the violations are the output. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
violations |
object[] |
yes | Each place a rule does not hold, empty when every rule held. | |
count |
integer |
yes | How many violations the analysis answered, at most max_results. |
|
duration_ms |
integer |
yes | How long the analysis took. |
Sensors¶
dhis2.data_set_complete¶
Wait for a DHIS2 data set to be marked complete.
Polls every 1m unless the step says otherwise. Gives up after 24h unless the step says otherwise.
Each poke reads /api/completeDataSetRegistrations once for the data set, period and
organisation unit. A registration carrying completed: false is a window that was reopened, so
the wait goes on; on an older instance, which answers without the flag, a registration's
existence is the completion.
Config
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
connection |
string |
yes | The code of the dhis2 connection naming the instance. | |
data_set |
string |
yes | The uid of the data set. | |
period |
string |
yes | An ISO period identifier, such as 2026Q1. | |
org_unit |
string |
yes | The uid of the organisation unit. |
Output
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
completed_at |
string or null |
null |
When the registration was made, in the instance's own timestamp. | |
stored_by |
string or null |
null |
Who marked the data set complete. |
How a failure is classified¶
Every block inherits one classifier, so retry policy means the same thing across the pack:
| What happened | Class |
|---|---|
| The instance answered 5xx | transient |
| The instance answered 429, rate limiting | transient |
| The instance answered any other 4xx, or refused the credential | rejected |
| The client does not speak the instance's version | rejected |
| A connection or read failure on the wire | transient |
A refusal's message is the instance's own words when it gave any: a DHIS2 web message's
message, and the reason phrase when the body was not one.
Every refusal carries a code¶
A refusal is catalogued: it carries a stable dotted code beside the sentence it renders, so a
stream of run records is selected by code however the English is later reworded --
jq 'select(.error_code == "dhis2.import.refused")'. The code is API and the text is not. The
codes from dhis2.analytics_query.no_program on are what a config refuses at validation.
| Code | Text |
|---|---|
dhis2.answered |
{where} answered {status}: {remote} |
dhis2.export.empty_answer |
{where} answered with an empty body rather than a data value set, which DHIS2 does when {org_unit} is outside the account's data scope; nothing was exported |
dhis2.unknown_uids |
{where} is scoped to uids the instance knows no object by: {unknown}; the read would answer nothing for them, so it was not made. Check the uids, or set require_known: false to read anyway |
dhis2.tracker.cap_reached |
reading every page of {kind} reached {cap} ({limit}) with rows still to read; nothing is answered rather than a part of the collection. Raise {cap} or narrow the read |
dhis2.task.no_reference |
the job submission answered without a task reference to follow: a job type and a task id, each one plain path segment |
dhis2.task.disappeared |
task {task} disappeared before its result could be collected |
dhis2.task.no_result |
task {task} has no result to collect: the instance holds no terminal notification for it |
dhis2.import.no_data_values |
data_values {found}, not a data value set with a dataValues list, so nothing was sent. A step's whole output passed where its document was meant is the usual cause: an export's document is steps.<step>.output.body, not steps.<step>.output |
dhis2.import.no_values_taken |
the instance took none of the {sent} values sent, and require_values asks for at least one: {detail} |
dhis2.import.no_summary |
{where} answered without an import summary, so nothing says the import took |
dhis2.import.unknown_status |
{where} answered a summary whose status is '{status}', so nothing says the import took |
dhis2.import.refused |
the import was refused: {detail} |
dhis2.import.took_nothing |
the import took nothing: {detail} |
dhis2.import.partial |
the import took {taken} values and refused {ignored} despite atomic_mode ALL: {detail} |
dhis2.import.conflicts_and_more |
{named} (and {more} more) |
dhis2.import.values_ignored |
{ignored} values ignored |
dhis2.connection.unreachable |
the instance did not answer: {detail} |
dhis2.connection.redirect_refused |
base_url on {configured} redirects to {target}, which is neither that host, a subdomain of it, nor under dhis2.org beside it, so the credential was not sent; set base_url to the target if it is yours |
dhis2.metadata.unknown_resource |
the instance's version knows no metadata resource named '{resource}' |
dhis2.message.no_recipient |
a message needs at least one recipient in users, user_groups or org_units |
dhis2.message.no_conversation |
{where} took the message but answered without the conversation it created |
dhis2.analytics_query.no_program |
a {mode} analytics query needs a program to read under |
dhis2.export.no_data |
a data value set export names what to read: a data_set, data_element or data_element_group |
dhis2.export.no_org_unit |
a data value set export names where to read: an org_unit or org_unit_group |
dhis2.export.no_period |
a data value set export names when to read: a period, a start_date with an end_date, last_updated or last_updated_duration |
dhis2.export.half_range |
start_date and end_date bound one range, so a data value set export takes both or neither |
dhis2.tracker.page_with_all_pages |
all_pages reads every page from the first, so it takes no page |
dhis2.connection.both_credentials |
a dhis2 connection takes an api_token or basic credentials, not both |
dhis2.connection.no_credential |
a dhis2 connection needs an api_token or basic credentials |
dhis2.connection.no_basic_password |
basic credentials need a basic_password beside the basic_username |
dhis2.connection.base_url_holds_more |
base_url says where the instance is and nothing else: a user, a password, a query or a fragment in it is refused, because it is stored as written; a credential goes in api_token or basic_password |
dhis2.connection.bad_api_token |
an api_token must be visible ASCII with no whitespace, or it cannot be sent as a header value |
dhis2.metadata_import.not_a_bundle |
a metadata bundle is an object keyed by collection, such as dataElements, and this one is {got} |
dhis2.metadata_import.no_report |
{where} answered without an import report, so nothing says the import took |
dhis2.metadata_import.refused |
the metadata import was refused: {detail} |
dhis2.tracker_import.not_a_bundle |
a tracker bundle is an object of trackedEntities, enrollments, events or relationships, and this one is {got} |
dhis2.tracker_import.no_report |
{where} answered without an import report, so nothing says the import took |
dhis2.tracker_import.no_job |
{where} accepted the import as a job but answered without a job id to follow |
dhis2.tracker_import.job_failed |
import job {job} ended in error without a report to read; the job said: {said} |
dhis2.tracker_import.refused |
the tracker import was refused: {detail} |
dhis2.data_value.no_value |
setting a data value needs a value |
dhis2.data_value.half_attribute |
attribute_combo and attribute_options name an attribute option combo together: give both or neither |
dhis2.data_value.unknown_attribute |
attribute combo {combo} has no option combo made of exactly the options {options} |
dhis2.data_value.refused |
the instance would not take the data value: {detail} |
dhis2.data_set_completion.refused |
the completion registration was refused: {detail} |
dhis2.export.format_unsupported |
DHIS2 {version} does not export a data value set as {format}, and answers JSON in its place; ADX is exported by 2.41 and 2.42, and every version imports it |
dhis2.import.not_text |
a {format} import sends its document as text, and data_values is {found}; give the document's text, or its storage URI as data_values_uri |
dhis2.import.two_sources |
data_values and data_values_uri each name the document to send, so an import takes one of them |
dhis2.data_store.no_key |
get, set and delete address one key, so they need a key |
dhis2.data_store.no_value |
setting a data store key needs a value to store |
dhis2.validation.violated |
validation rule analysis found {count} violations, and fail_on_violations asks for none: {detail} |
dhis2.predictor.both_targets |
a predictor run names one predictor or one predictor group, not both; name neither to run every predictor |