Skip to content

Slot Profile

Canonical../StructureDefinition/nexus-emr-core-slot
Statusdraft · 1.26.0
BaseSlot (constraint)
CQL primary code pathserviceTypewhat this means
SourceFSH · JSON

Minimal Nexus EMR profile for Slot resources — an individual bookable time window owned by a Schedule. Slots are materialised from recurring templates (Phase 1: OscarPro scheduletemplate rows) into concrete date+time instances. Booking clients select a free Slot, create an Appointment referencing it, and the booking system transitions the Slot's status.

TypedFhir API / Pydantic schema

The typed accessor surface Slot exposes for Slot — generated from this IG's compiled profile; each typed accessor has a validating raw-FHIR twin (xRaw) where marked. The three ports are parity-enforced.

The AI-facing shape: from typed_fhir.facade.generated.schemas import SlotSchemamodel_json_schema() is a structured-output / tool definition; instantiating validates an extraction. Generated source.

class SlotSchema(BaseModel):
    """AI-facing shape of the Slot profile: the facade's typed accessor
    surface (curated + salient fields) as a pydantic model. `model_json_schema()` is a
    structured-output / tool schema; instantiating validates an extraction."""

    model_config = ConfigDict(extra="forbid")

    service_category: Concept | None = Field(
        None,
        description=(
            "Service category with raw code support. A broad categorization of the service "
            "offered in this slot. RECOMMENDED: Standard terminology codes when available "
            "OPTIONAL: Raw EMR codes for source system preservation. The rawCode slice is `0..*` "
            "(not `1..*`) because the OscarPro source converter tolerates missing "
            "`scheduletemplatecode` lookups — slots can be emitted without a rawCode mapping. "
            "Note: Where this code was mapped from a source system's own vocabulary, carry the "
            "raw coding alongside the mapped one, flagged `userSelected = true`. See [Carrying "
            "the raw code](../guide/patterns/raw-codes.md). "
            "Slot.serviceCategory — 0..*"
        ),
    )
    service_type: Concept | None = Field(
        None,
        description=(
            "Service type with raw code support. The specific service offered in this slot. For "
            "OscarPro-sourced slots, the rawCode slice is populated from the corresponding "
            "`scheduletemplatecode` row (mapped via the single-character timecode value). The "
            "rawCode slice is `0..*` (not `1..*`) — see serviceCategory rationale above. Note: "
            "Where this code was mapped from a source system's own vocabulary, carry the raw "
            "coding alongside the mapped one, flagged `userSelected = true`. See [Carrying the "
            "raw code](../guide/patterns/raw-codes.md). Slot.serviceType "
            "— 0..*"
        ),
    )
    specialty: Concept | None = Field(
        None,
        description=(
            "The specialty of a practitioner that would be required to perform the service "
            "requested in this appointment. The specialty of a practitioner that would be "
            "required to perform the service requested in this appointment. Slot.specialty — "
            "0..*. codes (preferred): 394539006 | 394576009 | 394577000 | 394578005 | 394579002 | "
            "394580004 | 394581000 | 394582007 | …"
        ),
    )
    appointment_type: Concept | None = Field(
        None,
        description=(
            "Appointment type that fits this slot. The style of appointment this slot is intended "
            "for (e.g. routine, walk-in, checkup). Note: `Slot.appointmentType` and "
            "`Appointment.appointmentType` are independent in this IG — a booking client MAY "
            "create an Appointment with a different appointmentType than the slot it consumed. "
            "This supports flexible slot inventory (e.g. a clinic that double-purposes a slot for "
            "either routine or walk-in). RECOMMENDED that booking clients copy the slot's "
            "appointmentType to the resulting Appointment but not REQUIRED. Note: Where this code "
            "was mapped from a source system's own vocabulary, carry the raw coding alongside the "
            "mapped one, flagged `userSelected = true`. See [Carrying the raw "
            "code](../guide/patterns/raw-codes.md). Slot.appointmentType "
            "— 0..1. codes (preferred): CHECKUP | EMERGENCY | FOLLOWUP | ROUTINE | WALKIN"
        ),
    )
    schedule: Reference | None = Field(
        None,
        description=(
            "The Schedule this Slot belongs to. The Schedule resource that this Slot is derived "
            "from. Required per base FHIR R4 (Slot.schedule cardinality 1..1). Slot.schedule — "
            "1..1"
        ),
    )
    status: Literal[
        "busy",
        "busy-tentative",
        "busy-unavailable",
        "entered-in-error",
        "free",
    ] | None = Field(
        None,
        description=(
            "busy | free | busy-unavailable | busy-tentative | entered-in-error. The free/busy "
            "state of the slot. The IG does NOT constrain who writes this field. Phase 1 contract "
            "(see profile intro): - Oscar-side converter writes 'free' (default) or 'busy' (when "
            "an appointment row overlaps the slot window) or 'busy-unavailable' (within-day "
            "blockout from ScheduleDate.available != '1'). - Booking system writes "
            "'busy-tentative' during a hold flow, then transitions to 'busy' on confirm or back "
            "to 'free' on hold timeout. - The converter NEVER writes 'busy-tentative' — that "
            "value is the booking system's exclusively. Slot.status — 1..1"
        ),
    )
    start: FuzzyDate | None = Field(
        None,
        description=(
            "Slot start instant (UTC with offset). Date/Time at which this slot starts. "
            "Source-system local time is converted to UTC with offset by the converter (Phase 1: "
            "province → IANA TZ lookup based on the clinic's Location.address). Slot.start — 1..1"
        ),
    )
    end: FuzzyDate | None = Field(
        None,
        description=(
            "Slot end instant (UTC with offset). Date/Time at which this slot ends. For a slot "
            "derived from a 15-minute template grid, end = start + 15 minutes. Slot duration is "
            "constant within a template (computed as 1440 / timecode.length() minutes per slot). "
            "Slot.end — 1..1"
        ),
    )
    overbooked: bool | None = Field(
        None,
        description=(
            "Whether the slot is intentionally overbooked. Set by the booking system when more "
            "than one appointment is booked into the same slot window (e.g. walk-in over a held "
            "slot). Informational; the IG does not enforce a maximum. Slot.overbooked — 0..1"
        ),
    )
    comment: str | None = Field(
        None,
        description=(
            "Free-text notes about the slot (e.g. blockout reason). Used to carry the "
            "ScheduleDate.reason text when a within-day blockout produces a busy-unavailable "
            "Slot. Slot.comment — 0..1"
        ),
    )