Skip to content

Tracker reads

Typed instance models returned by /api/tracker/* reads: TrackerTrackedEntity, TrackerEnrollment, TrackerEvent, TrackerRelationship + nested value types + EventStatus / EnrollmentStatus StrEnums.

Tracker models are version-scoped because /api/tracker/* shapes drift across DHIS2 majors. Import from the version your client is pinned to: from dhis2w_client.generated.v43.tracker import TrackerBundle, TrackerEvent, .... The matching write path lives on client.tracker (register / enroll / add_event / outstanding) — see the tracker plugin architecture.

When to reach for it

  • Reading instance data from /api/tracker/trackedEntities, /api/tracker/enrollments, /api/tracker/events with typed results.
  • Parsing a raw tracker bundle response (e.g. from a file fixture or a webhook) into typed models before processing.
  • Branching on EventStatus / EnrollmentStatus exhaustively via match.

Worked example — read tracked entities, enrollments, events

client.tracker.tracked_entities, .enrollments, and .events are the read side of the write verbs below. Each GETs the matching /api/tracker/* endpoint with the standard query surface: program, org_unit (one id or a sequence) with ou_mode, status, fields, filter, page / page_size, updated_after (an ISO string, a date, or a datetime), and extra_params for the rest (order, enrolledAfter, assignedUser, ...). events also scopes by program_stage, enrollment, and occurred_after. status filters by enrollment status on the first two reads and by event status on events.

The page envelope is returned as parsed JSON: the rows live under instances on current majors, and under the resource's own name on older minors, beside the paging fields. Parse a row with the generated model when a typed view is wanted:

from dhis2w_client.generated.v43.tracker import TrackerEvent
from dhis2w_core.client_context import open_client
from dhis2w_core.profile import profile_from_env


async with open_client(profile_from_env()) as client:
    page = await client.tracker.events(
        program="IpHINAT79UW",
        org_unit="ImspTQPwCqd",
        ou_mode="DESCENDANTS",
        occurred_after="2026-01-01",
        page_size=10,
    )
    for row in page.get("instances") or page.get("events") or []:
        event = TrackerEvent.model_validate(row)
        print(f"{event.event}  status={event.status}  ou={event.orgUnit}")

Worked example — register a tracked entity, enroll, add events

The write side lives on client.tracker. register returns a typed RegisterResult carrying the freshly-generated UIDs + the underlying WebMessageResponse; add_event returns an EventResult with the new event UID + its response envelope:

async with open_client(profile_from_env()) as client:
    # 1. Register a new tracked entity + enroll in one call.
    result = await client.tracker.register(
        program="IpHINAT79UW",
        org_unit="DiszpKrYNg8",
        tracked_entity_type="nEenWmSyUEp",
        attributes={"w75KJ2mc4zz": "Jane", "zDhUuAYrxNC": "Doe"},
    )
    print(f"TE={result.tracked_entity}  enrollment={result.enrollment}  status={result.response.status}")

    # 2. Add an event to the new enrollment.
    event = await client.tracker.add_event(
        program="IpHINAT79UW",
        program_stage="A03MvHHogjR",
        enrollment=result.enrollment,
        org_unit="DiszpKrYNg8",
        data_values={"a3kGcGDCuk6": "BCG"},
    )
    print(f"event={event.event}  status={event.response.status}")

Worked example — outstanding follow-up

async with open_client(profile_from_env()) as client:
    # ACTIVE enrollments missing events on a non-repeatable stage —
    # the "what's due" report. `program` is positional; `org_unit`
    # narrows the OU subtree (DESCENDANTS by default).
    rows = await client.tracker.outstanding("IpHINAT79UW", org_unit="ImspTQPwCqd")
    for row in rows:
        print(f"  enrollment={row.enrollment}  TE={row.tracked_entity}  missing={row.missing_stages}")

tracker

Typed models for DHIS2 v43 tracker instance data.

Thin shim over the OpenAPI-derived models under generated/v43/oas/. Re-exports the wire-shape classes (TrackerTrackedEntity, TrackerEnrollment, TrackerEvent, TrackerRelationship, TrackerRelationshipItem, TrackerDataValue, TrackerAttribute, TrackerNote) plus the status enums (EnrollmentStatus, EventStatus), and defines the client-side TrackerBundle wrapper used for POST /api/tracker (not in OpenAPI — it's the wire envelope DHIS2 accepts for bulk writes).

DHIS2 v43's OpenAPI exposes the event schema under the redundant name TrackerTrackerEvent (vs TrackerEvent in v42). The alias below keeps the public name TrackerEvent stable across versions; see BUGS.md for the upstream naming quirk.

Classes

EnrollmentStatus

Bases: StrEnum

EnrollmentStatus.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/_enums.py
class EnrollmentStatus(StrEnum):
    """EnrollmentStatus."""

    ACTIVE = "ACTIVE"
    COMPLETED = "COMPLETED"
    CANCELLED = "CANCELLED"

EventStatus

Bases: StrEnum

EventStatus.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/_enums.py
class EventStatus(StrEnum):
    """EventStatus."""

    ACTIVE = "ACTIVE"
    COMPLETED = "COMPLETED"
    VISITED = "VISITED"
    SCHEDULE = "SCHEDULE"
    OVERDUE = "OVERDUE"
    SKIPPED = "SKIPPED"

TrackerAttribute

Bases: BaseModel

OpenAPI schema TrackerAttribute.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_attribute.py
class TrackerAttribute(_BaseModel):
    """OpenAPI schema `TrackerAttribute`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    attribute: str | None = None
    code: str | None = None
    createdAt: Instant | None = None
    displayName: str | None = None
    storedBy: str | None = None
    updatedAt: Instant | None = None
    value: str | None = None
    valueType: ValueType | None = None

TrackerDataValue

Bases: BaseModel

OpenAPI schema TrackerDataValue.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_data_value.py
class TrackerDataValue(_BaseModel):
    """OpenAPI schema `TrackerDataValue`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    createdAt: Instant | None = None
    createdBy: TrackerUser | None = None
    dataElement: str | None = None
    providedElsewhere: bool | None = None
    storedBy: str | None = None
    updatedAt: Instant | None = None
    updatedBy: TrackerUser | None = None
    value: str | None = None

TrackerEnrollment

Bases: BaseModel

OpenAPI schema TrackerEnrollment.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_enrollment.py
class TrackerEnrollment(_BaseModel):
    """OpenAPI schema `TrackerEnrollment`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    attributeOptionCombo: str | None = None
    attributes: list[TrackerAttribute] | None = None
    completedAt: Instant | None = None
    completedBy: str | None = None
    createdAt: Instant | None = None
    createdAtClient: Instant | None = None
    createdBy: TrackerUser | None = None
    deleted: bool | None = None
    enrolledAt: Instant | None = None
    enrollment: str | None = None
    events: list[Event] | None = None
    followUp: bool | None = None
    geometry: dict[str, Any] | None = None
    notes: list[TrackerNote] | None = None
    occurredAt: Instant | None = None
    orgUnit: str | None = None
    program: str | None = None
    relationships: list[TrackerRelationship] | None = None
    status: EnrollmentStatus | None = None
    storedBy: str | None = None
    trackedEntity: str | None = None
    updatedAt: Instant | None = None
    updatedAtClient: Instant | None = None
    updatedBy: TrackerUser | None = None

TrackerNote

Bases: BaseModel

OpenAPI schema TrackerNote.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_note.py
class TrackerNote(_BaseModel):
    """OpenAPI schema `TrackerNote`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    createdBy: TrackerUser | None = None
    note: str | None = None
    storedAt: Instant | None = None
    storedBy: str | None = None
    value: str | None = None

TrackerRelationship

Bases: BaseModel

OpenAPI schema TrackerRelationship.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_relationship.py
class TrackerRelationship(_BaseModel):
    """OpenAPI schema `TrackerRelationship`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    bidirectional: bool | None = None
    createdAt: Instant | None = None
    createdAtClient: Instant | None = None
    from_: TrackerRelationshipItem | None = _Field(default=None, alias="from")
    relationship: str | None = None
    relationshipName: str | None = None
    relationshipType: str | None = None
    to: TrackerRelationshipItem | None = None
    updatedAt: Instant | None = None

TrackerRelationshipItem

Bases: BaseModel

OpenAPI schema TrackerRelationshipItem.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_relationship_item.py
class TrackerRelationshipItem(_BaseModel):
    """OpenAPI schema `TrackerRelationshipItem`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    enrollment: TrackerRelationshipItemEnrollment | None = None
    event: TrackerRelationshipItemEvent | None = None
    trackedEntity: TrackerRelationshipItemTrackedEntity | None = None

TrackerTrackedEntity

Bases: BaseModel

OpenAPI schema TrackerTrackedEntity.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_tracked_entity.py
class TrackerTrackedEntity(_BaseModel):
    """OpenAPI schema `TrackerTrackedEntity`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    attributes: list[TrackerAttribute] | None = None
    createdAt: Instant | None = None
    createdAtClient: Instant | None = None
    createdBy: TrackerUser | None = None
    deleted: bool | None = None
    enrollments: list[TrackerEnrollment] | None = None
    geometry: dict[str, Any] | None = None
    inactive: bool | None = None
    orgUnit: str | None = None
    potentialDuplicate: bool | None = None
    programOwners: list[TrackerProgramOwner] | None = None
    relationships: list[TrackerRelationship] | None = None
    storedBy: str | None = None
    trackedEntity: str | None = None
    trackedEntityType: str | None = None
    updatedAt: Instant | None = None
    updatedAtClient: Instant | None = None
    updatedBy: TrackerUser | None = None

TrackerEvent

Bases: BaseModel

OpenAPI schema TrackerTrackerEvent.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/oas/tracker_tracker_event.py
class TrackerTrackerEvent(_BaseModel):
    """OpenAPI schema `TrackerTrackerEvent`."""

    model_config = _ConfigDict(extra="allow", populate_by_name=True, defer_build=True)

    assignedUser: TrackerUser | None = None
    attributeOptionCombo: str | None = None
    completedAt: Instant | None = None
    completedBy: str | None = None
    createdAt: Instant | None = None
    createdAtClient: Instant | None = None
    createdBy: TrackerUser | None = None
    dataValues: list[TrackerDataValue] | None = None
    deleted: bool | None = None
    enrollment: str | None = None
    event: str | None = None
    followUp: bool | None = None
    geometry: dict[str, Any] | None = None
    notes: list[TrackerNote] | None = None
    occurredAt: Instant | None = None
    orgUnit: str | None = None
    program: str | None = None
    programStage: str | None = None
    relationships: list[TrackerRelationship] | None = None
    scheduledAt: Instant | None = None
    status: EventStatus | None = None
    storedBy: str | None = None
    trackedEntity: str | None = None
    updatedAt: Instant | None = None
    updatedAtClient: Instant | None = None
    updatedBy: TrackerUser | None = None

TrackerBundle

Bases: BaseModel

Typed payload for POST /api/tracker — any mix of tracker objects in one atomic write.

DHIS2 accepts nested construction (a tracked entity carrying its own enrollments[] which carry their own events[]) or flat construction (all four arrays populated independently). Callers pick whichever fits their data shape; DHIS2 collapses both forms server-side.

Produce the wire payload with bundle.model_dump(by_alias=True, exclude_none=True, mode="json"). Bundle fields are typed lists of the OpenAPI-derived tracker models, so enum fields like EventStatus.COMPLETED validate at construction time.

Not in the OpenAPI spec — POST /api/tracker is documented but the request body shape is described only in prose. This class is a hand-written mirror of that shape.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v43/tracker.py
class TrackerBundle(BaseModel):
    """Typed payload for `POST /api/tracker` — any mix of tracker objects in one atomic write.

    DHIS2 accepts nested construction (a tracked entity carrying its own
    `enrollments[]` which carry their own `events[]`) or flat construction
    (all four arrays populated independently). Callers pick whichever fits
    their data shape; DHIS2 collapses both forms server-side.

    Produce the wire payload with
    `bundle.model_dump(by_alias=True, exclude_none=True, mode="json")`.
    Bundle fields are typed lists of the OpenAPI-derived tracker models, so
    enum fields like `EventStatus.COMPLETED` validate at construction time.

    Not in the OpenAPI spec — `POST /api/tracker` is documented but the
    request body shape is described only in prose. This class is a
    hand-written mirror of that shape.
    """

    model_config = ConfigDict(extra="allow")

    trackedEntities: list[TrackerTrackedEntity] = Field(default_factory=list)
    enrollments: list[TrackerEnrollment] = Field(default_factory=list)
    events: list[TrackerEvent] = Field(default_factory=list)
    relationships: list[TrackerRelationship] = Field(default_factory=list)