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.v42.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 — typed reads via get_raw + model_validate

from dhis2w_client.generated.v42.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:
    # Tracker reads land via raw paths today; the typed models above are
    # the parse target. The accessor surface (`client.tracker.*`) covers
    # writes; reads are still raw-path-based.
    raw = await client.get_raw(
        "/api/tracker/events",
        params={
            "program": "IpHINAT79UW",
            "orgUnit": "ImspTQPwCqd",
            "ouMode": "DESCENDANTS",
            "pageSize": "10",
        },
    )
    for row in raw.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}  "
        f"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}  "
            f"missing={row.missing_stages}"
        )

tracker

Typed models for DHIS2 v42 tracker instance data.

Thin shim over the OpenAPI-derived models under generated/v42/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).

Tracker shapes drift across DHIS2 majors; keeping this under dhis2w_client.generated.v42 means a v43 bump can ship its own generated/v43/oas/ + tracker.py without touching v42 callers.

Classes

EnrollmentStatus

Bases: StrEnum

EnrollmentStatus.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v42/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/v42/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/v42/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/v42/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/v42/oas/tracker_enrollment.py
class TrackerEnrollment(_BaseModel):
    """OpenAPI schema `TrackerEnrollment`."""

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

    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[TrackerEvent] | 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

TrackerEvent

Bases: BaseModel

OpenAPI schema TrackerEvent.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v42/oas/tracker_event.py
class TrackerEvent(_BaseModel):
    """OpenAPI schema `TrackerEvent`."""

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

    assignedUser: TrackerUser | None = None
    attributeCategoryOptions: str | 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

TrackerNote

Bases: BaseModel

OpenAPI schema TrackerNote.

Source code in packages/dhis2w-client/src/dhis2w_client/generated/v42/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/v42/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/v42/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/v42/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

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/v42/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)