Skip to main content
The haau3 Scheduling API is a Slot Aggregator for SMART Scheduling Links (SSL). It ingests provider availability from many SSL publishers and serves it through one key-authenticated API. A Slot Discovery Client can search every publisher by calling the Scheduling API, instead of integrating with each publisher separately. The open-source SDKs for TypeScript, Python and Go call every operation of this service, and each operation in the API reference has a sample in all three and in cURL. SMART Scheduling Links is an HL7 specification for publishing open appointment availability. A publisher exposes a $bulk-publish manifest that points at NDJSON files of FHIR resources: Schedule, Slot, and the actors they reference (Location, Practitioner, PractitionerRole, HealthcareService). Anyone can poll the manifest to see what’s bookable and send patients to the publisher’s booking link.

The roles in SSL

The IG defines a small set of roles:
  • Slot Publisher: a healthcare provider’s API that advertises its available slots.
  • Provider Booking Portal: the provider’s UI where a patient books a slot.
  • Slot Aggregator: a third-party API that combines data from multiple Slot Publishers and offers unified search across them. It does not own the underlying data.
  • Slot Discovery Client: the patient’s booking tool. It searches for slots and sends the patient to the right portal to finish booking.
The haau3 Scheduling API is a Slot Aggregator. A Slot Discovery Client queries it once and gets consistent results across every publisher the API ingests, rather than polling and reconciling each publisher’s $bulk-publish feed itself. haau3 also operates a reference Slot Publisher, its own openly fetchable $bulk-publish feed, so you can test a direct publisher connection while evaluating the aggregator. It is a contribution to the open standard. It is not a separate product. See Slot Publisher.

What the Scheduling API does as the aggregator

The Scheduling API turns raw publisher feeds into one queryable model in three steps:
  • Ingest: each publisher’s latest $bulk-publish snapshot is downloaded and tracked.
  • Validate: every resource is checked for base FHIR R4 validity, then against the SMART Scheduling Links 1.0.0 profiles (continuous build of October 6, 2026) with strict referential integrity. A publisher’s live production feed must meet every element the profiles require. A feed from a publisher still testing its implementation may use the May 2026 ballot’s shape where 1.0.0 tightened it: acceptance in appointmentType instead of the patient-type extension, and booking-phone as a string. Records that don’t conform are quarantined and kept out of the served data.
  • Normalize: conforming slots are flattened into a denormalized Slot shape with its source publisher, status, start and end times, service types (every coding, with its system), the schedule’s specialties, accepting-patients code, an expanded location (name, description, telecom, address, coordinates, physical type), provider (a practitioner, or a healthcare service when the schedule names no practitioner, with its coded specialties), isVirtual, and source (the publisher’s own id for the slot, the publisher’s snapshot time, and when the API last read it). Fields a source omits stay absent; the API adds nothing.
Quarantine keeps bad data out of the API, but the haau3 team also works directly with publishers to flag nonconformant slots so issues get fixed at the source. This keeps the served data at a consistently high quality over time.

Limits on a feed

Each cycle reads a publisher’s feed within these limits:

Querying availability

Five endpoints serve the model. See the API Reference for full details.
  • GET /v1/scheduling/slots: search availability with filters (status, publisher, service type, provider NPI, specialty, city, state, virtual, time window, accepting-patients) and pagination. Results start from now: with no startAfter, a slot that started before the request is left out unless you pass includePast=true, and an explicit startAfter applies as given. Every slot carries its source publisher, and publisher=<slug> narrows results to one publisher (useful for a publisher inspecting just its own slots). serviceTypeCode matches a slot when any of its serviceTypes carries the code. npi matches a slot whose provider carries that National Provider Identifier (ten digits), a clinician’s or an organization’s, across every publisher. specialty matches a slot when its provider’s specialties or its schedule’s specialties carry the code: send code to match it in any code system, or system|code for one system. Specialty codes are each publisher’s own and are not translated between code systems, so a code finds the publishers that use it, and a specialty a publisher sends as text only cannot be matched. serviceTypeCode, npi and specialty each take a comma-separated list of up to 100 values and match a slot carrying any of them. The acceptingPatients filter (HL7 accepting-patients codes newpt, existptonly and existptfam) is lenient: a slot that does not declare an acceptance code still matches any requested value (absence never hides a slot), while a slot that declares one must equal it. A slot a source marks nopt (not accepting patients) is never served: it is not real availability, so it never appears in results regardless of the filter.
  • GET /v1/scheduling/provider-locations: the matching slots grouped by provider location. One entry per provider at a location, or per location when a slot names no provider, aggregated server side, with exact counts and soonest availability over the full match set. It takes the same filters as /slots except providerLocationKey, including includePast. Paginated by provider location; each one’s key returns its slots through /slots?providerLocationKey=<key>.
  • GET /v1/scheduling/publishers: list the registered publishers, each with an enabled flag (the slug values accepted by the publisher filter). A publisher can be listed and not currently ingesting, so check enabled rather than assuming every slug returns slots.
  • GET /v1/scheduling/service-types: list the distinct service types observed across served slots, each with its system and a count of the slots carrying it: a discovery aid for the serviceTypeCode filter (the values it accepts), self-healing as publishers change. Like /slots, it counts slots from now unless you pass includePast=true, and only from enabled publishers.
  • GET /v1/scheduling/specialties: list the distinct specialties observed across served slots, from the provider’s specialties and the schedule’s, each with its system and a count of the slots carrying it: the values the specialty filter accepts, in each publisher’s own code system. It follows the same rules as /service-types.
All five require a valid API key (see Authentication). For your first call, start with the Quickstart. All five answer from live data or not at all. If the scheduling service is unavailable or slow they return 503, an RFC 9457 problem with Retry-After. They never fall back to sample or placeholder data, so a 200 is always a real answer. Treat a 503 as retryable; a malformed request still returns 400 with issues naming each parameter at fault, so the two are always distinguishable. A parameter an endpoint does not take, or one sent twice, is refused the same way: see parameters.

Standards status

SMART Scheduling Links went to HL7 ballot in May 2026 as 1.0.0-ballot. Its continuous build, dated October 6, 2026, carries the ballot’s resolutions as version 1.0.0 (STU 1). It is not yet an authorized publication. The Scheduling API validates publisher feeds against the 1.0.0 build’s profiles. That build changed three things a feed carries: every Slot has a patient-type extension saying whether it is open to new or existing patients, booking-phone is a ContactPoint, and a Location no longer needs an identifier or an address. A feed from a publisher still testing its implementation may keep the ballot’s form of the first two, as described under Validate above. SMART Scheduling Links builds on FHIR Bulk Publish, the mechanism for distributing static, pre-generated FHIR datasets (provider directories, formularies, scheduling, and similar) through a $bulk-publish manifest. Bulk Publish is part of version 4 of the HL7 Bulk Data Access IG, balloted as 4.0.0-ballot (see its publish operation). The current published version of that IG, 3.0.0, does not include it.