> ## Documentation Index
> Fetch the complete documentation index at: https://docs.maxcare.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Find bookable slots

> Bookable slots for an appointment type across providers and a date window. `meta.strategy` records whether the EHR answered natively or Max AI synthesised the list — it is there for support, not for branching. `remainingCapacity` already has booked appointments and active holds subtracted. Pass `consistency=strong` for the final pre-write check.



## OpenAPI

````yaml /openapi-v3.json get /schedule/slots
openapi: 3.0.0
info:
  title: Max AI Public API
  description: API for third-party marketplace apps
  version: '3.0'
  contact: {}
servers:
  - url: https://api.maxcare.ai/v3
security: []
tags: []
paths:
  /schedule/slots:
    get:
      tags:
        - Schedule
      summary: Find bookable slots
      description: >-
        Bookable slots for an appointment type across providers and a date
        window. `meta.strategy` records whether the EHR answered natively or Max
        AI synthesised the list — it is there for support, not for branching.
        `remainingCapacity` already has booked appointments and active holds
        subtracted. Pass `consistency=strong` for the final pre-write check.
      operationId: SchedulePublicController_findSlots
      parameters:
        - name: appointmentTypeId
          required: true
          in: query
          description: Appointment type ID (atp_…)
          schema:
            type: string
        - name: facilityId
          required: false
          in: query
          description: Facility ID (fac_…). Repeat or comma-separate for several.
          schema:
            type: string
        - name: providerIds
          required: false
          in: query
          description: Comma-separated provider IDs (prv_…)
          schema:
            type: string
        - name: from
          required: true
          in: query
          description: Window start (YYYY-MM-DD, inclusive)
          schema:
            example: '2026-08-01'
            type: string
        - name: to
          required: true
          in: query
          description: Window end (YYYY-MM-DD, inclusive)
          schema:
            example: '2026-08-07'
            type: string
        - name: durationMinutes
          required: false
          in: query
          description: Slot length in minutes. Defaults to the appointment type's default.
          schema:
            type: number
            example: 15
        - name: newPatient
          required: false
          in: query
          description: Search as a new patient (changes type defaults on both EHRs)
          schema:
            type: boolean
            example: true
        - name: consistency
          required: false
          in: query
          description: >-
            Set to `strong` for the final pre-write validation: bypasses caches
            and reads the EHR live. Slower; use it once, not per keystroke.
          schema:
            example: strong
            type: string
        - name: X-Organization-Id
          in: header
          required: true
          schema:
            type: string
          description: Target clinic organization ID
      responses:
        '200':
          description: Success
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/FindSlotsSuccessResponse'
        '400':
          description: Missing or invalid request parameter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiBadRequestResponse'
        '401':
          description: Invalid or missing API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiUnauthorizedResponse'
        '403':
          description: Insufficient scope
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiForbiddenResponse'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiRateLimitResponse'
        '502':
          description: EHR sync failed
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiBadGatewayResponse'
        '503':
          description: EHR integration unavailable
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiServiceUnavailableResponse'
      security:
        - api-key: []
components:
  schemas:
    FindSlotsSuccessResponse:
      type: object
      properties:
        code:
          type: string
          description: Response code
          example: success
        data:
          $ref: '#/components/schemas/FindSlotsData'
      required:
        - code
        - data
    PublicApiBadRequestResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: bad_request
        message:
          type: string
          description: Human-readable error message
          example: '''id'' must be a valid UUID'
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiUnauthorizedResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: unauthorized
        message:
          type: string
          description: Human-readable error message
          example: Invalid or missing API key
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiForbiddenResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: forbidden
        message:
          type: string
          description: Human-readable error message
          example: Insufficient scope
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiRateLimitResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: rate_limit_exceeded
        message:
          type: string
          description: Human-readable error message
          example: Rate limit exceeded. Maximum 1000 requests per 60 seconds.
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiBadGatewayResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: unexpected_integration_error
        message:
          type: string
          description: Human-readable error message
          example: EHR sync failed
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiServiceUnavailableResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: server_unresponsive
        message:
          type: string
          description: Human-readable error message
          example: EHR integration is not available for this note
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    FindSlotsData:
      type: object
      properties:
        slots:
          type: array
          items:
            $ref: '#/components/schemas/SlotResponse'
        nextAvailableByProvider:
          type: object
          description: >-
            providerId → ISO date of that provider's earliest bookable day
            INSIDE the requested window. Always a day within `[from, to]`, and
            always derivable from `slots`. A provider with nothing bookable in
            the window is ABSENT from this map: absence means nothing is
            available for them in the window you searched. It never reports a
            day beyond `to` — days the EHR happens to surface while paging are
            not carried over, because a caller cannot distinguish one of those
            from a day actually verified against the ledger. To look further
            out, widen `to` and search again. Holds are already subtracted, so a
            listed day always has at least one bookable slot in `slots`.
          example:
            prv_38486585aaaa4bbbccccddddeeeeffff: '2026-08-28'
        meta:
          $ref: '#/components/schemas/SlotSearchMetaResponse'
      required:
        - slots
        - nextAvailableByProvider
        - meta
    SlotResponse:
      type: object
      properties:
        providerId:
          type: string
          example: prv_35103413aaaa4bbbccccddddeeeeffff
        facilityId:
          type: string
          example: fac_2706aaaa4bbbccccddddeeeeffff1111
        startsAt:
          type: string
          example: '2026-08-03T08:00:00-04:00'
        endsAt:
          type: string
          example: '2026-08-03T08:15:00-04:00'
        remainingCapacity:
          type: number
          description: >-
            Free capacity: overlapping template concurrency, minus booked
            appointments, minus active holds
          example: 2
        templateIds:
          example:
            - avt_9f2c1d0e3b4a5968778695a4b3c2d1e0
          type: array
          items:
            type: string
      required:
        - providerId
        - facilityId
        - startsAt
        - endsAt
        - remainingCapacity
        - templateIds
    SlotSearchMetaResponse:
      type: object
      properties:
        sourceSyncedAt:
          type: string
          description: >-
            When the underlying data was last synced from, or read from, the
            EHR. Null means complete sync coverage for the requested scope and
            dates is unknown. Read `sourceKind` before treating this as a lag
            measurement — on a live read it is the moment of the read itself, so
            `now - sourceSyncedAt` is always ~0 and measures nothing.
          nullable: true
          example: '2026-07-26T12:59:31.000Z'
        sourceKind:
          type: string
          enum:
            - live_read
            - mirror
          description: >-
            What `sourceSyncedAt` actually is. `live_read`: the endpoint went to
            the EHR for this request, so the timestamp is the read time and
            there is no lag to measure. `mirror`: the timestamp is a real sync
            watermark and `now - sourceSyncedAt` IS the lag. Slot searches use
            `mirror` unless strong consistency is requested. A consumer
            computing mirror lag must skip `live_read` responses rather than
            average a structural zero into its numbers.
          example: live_read
        maxStalenessSeconds:
          type: number
          description: The staleness this endpoint is designed to stay within, in seconds
          example: 60
        strongConsistency:
          type: boolean
          description: >-
            Whether the response bypassed caches and read the EHR live
            (`?consistency=strong`)
          example: false
        strategy:
          type: string
          description: >-
            How the slot grid was produced. Do NOT branch on it — use
            `completeness` for that. `synthesized` is now the normal answer for
            BOTH EHRs, because the default grid is materialised from Max AI's
            own capacity ledger (templates minus blocking events) rather than
            asked of the vendor per request. `native` appears only under
            `?consistency=strong` on an EHR with a bulk availability endpoint,
            where the vendor computes the grid itself. Under either, capacity is
            decided by the EHR's RAW status and never by the normalized `status`
            on the appointments read: an appointment consumes a slot when its
            vendor status is scheduled/confirmed/arrived/in-progress/completed,
            while cancellations, no-shows and reschedules free it. Platform-side
            slot holds are subtracted on top in all cases.
          example: synthesized
          enum:
            - native
            - synthesized
        completeness:
          type: string
          description: >-
            Whether this grid is the WHOLE truth or a floor — the field to
            branch on when it matters. `complete`: every bookable window the
            practice defines is represented, so an absent slot really is
            unavailable. `lower_bound`: real availability may EXCEED what is
            listed, because this EHR exposes no readable availability-template
            surface and Max AI reconstructs windows by probing for free slots.
            Two consequences: a fully-booked window is invisible to us, and
            per-window concurrency cannot be read, so a clinic that sees two
            patients at once is reported as seeing one. Under-offering is the
            safe direction — nothing here can cause a double-book — but a
            consumer showing 'no availability' should say 'none bookable online'
            rather than 'the practice is full', and may want to offer a
            call-the-office path. Applies to EZDerm today; ModMed is `complete`.
          example: complete
          enum:
            - complete
            - lower_bound
        generatedAt:
          type: string
          description: When the slot list was computed
          example: '2026-07-26T09:00:01.000Z'
      required:
        - sourceSyncedAt
        - sourceKind
        - maxStalenessSeconds
        - strongConsistency
        - strategy
        - completeness
        - generatedAt
  securitySchemes:
    api-key:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Marketplace API key

````