> ## 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.

# List a patient's chart documents

> Returns the documents on the patient's chart in the source EHR — insurance cards, photo identification, prior-authorization paperwork and clinical files — with the EHR's own category passed through as `sourceCategory` and a best-effort `kind`. Serves the cached listing, so it makes no EHR calls and is safe to poll; use `updatedSince` for delta sync. A document whose bytes have never been pulled from the EHR is returned with `downloaded: false` and no `url` rather than omitted. The envelope names the chart this listing came from (`ehrType`, `ehrPatientId`) and whether it can still be re-listed (`ehrActive`) — a practice running two EHRs holds a separate record per EHR for the same human, each with its own documents. Requires read:patient_documents scope.



## OpenAPI

````yaml /openapi-v1.json get /patients/{id}/documents
openapi: 3.0.0
info:
  title: Max AI Public API
  description: API for third-party marketplace apps
  version: '1.0'
  contact: {}
servers:
  - url: https://api.maxcare.ai/v1
security: []
tags: []
paths:
  /patients/{id}/documents:
    get:
      tags:
        - Patients
      summary: List a patient's chart documents
      description: >-
        Returns the documents on the patient's chart in the source EHR —
        insurance cards, photo identification, prior-authorization paperwork and
        clinical files — with the EHR's own category passed through as
        `sourceCategory` and a best-effort `kind`. Serves the cached listing, so
        it makes no EHR calls and is safe to poll; use `updatedSince` for delta
        sync. A document whose bytes have never been pulled from the EHR is
        returned with `downloaded: false` and no `url` rather than omitted. The
        envelope names the chart this listing came from (`ehrType`,
        `ehrPatientId`) and whether it can still be re-listed (`ehrActive`) — a
        practice running two EHRs holds a separate record per EHR for the same
        human, each with its own documents. Requires read:patient_documents
        scope.
      operationId: PatientsPublicController_listPatientDocuments
      parameters:
        - name: id
          required: true
          in: path
          description: Patient ID
          schema:
            type: string
        - name: page
          required: false
          in: query
          description: Page number (1-indexed)
          schema:
            default: 1
            example: 1
        - name: pageSize
          required: false
          in: query
          description: Number of items per page (max 100)
          schema:
            default: 100
            example: 100
        - name: kind
          required: false
          in: query
          description: Filter to a single document kind.
          schema:
            example: insurance_card
            enum:
              - insurance_card
              - identification
              - prior_auth
              - clinical
              - other
            type: string
        - name: updatedSince
          required: false
          in: query
          description: >-
            Delta sync: only documents whose record changed at or after this
            instant (ISO 8601). Compared against `updatedAt`. Pair with
            `includeDeleted=true` to also learn about documents removed from the
            chart since the cursor — without it a delta poll reports additions
            and changes only.
          schema:
            example: '2026-08-01T00:00:00.000Z'
            type: string
        - name: includeDeleted
          required: false
          in: query
          description: >-
            Include documents that have since been removed from the EHR chart
            (they carry `deletedFromEhrAt`). Defaults to false: a removed
            document is normally noise, and because removal is the newest thing
            that happened to it, it would otherwise sort to the top of the list.
          schema:
            default: false
            example: false
            type: boolean
        - 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/ListPatientDocumentsSuccessResponse'
        '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'
        '404':
          description: Resource not found
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiNotFoundResponse'
        '429':
          description: Rate limit exceeded
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiRateLimitResponse'
      security:
        - api-key: []
components:
  schemas:
    ListPatientDocumentsSuccessResponse:
      type: object
      properties:
        code:
          type: string
          description: Response code
          example: success
        data:
          $ref: '#/components/schemas/ListPatientDocumentsResponseData'
      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
    PublicApiNotFoundResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: not_found
        message:
          type: string
          description: Human-readable error message
          example: Resource not found
        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
    ListPatientDocumentsResponseData:
      type: object
      properties:
        documents:
          type: array
          items:
            $ref: '#/components/schemas/ExternalPatientDocumentResponse'
        ehrType:
          type: string
          description: >-
            Which EHR these documents were listed from ('ezderm', 'modmed'),
            read from the chart's own EHR instance. Present here, and not only
            on the patient resource, because a practice running two EHRs holds a
            separate record per EHR for the same human and each record has its
            OWN document list — so a listing that looks complete may simply be
            the wrong chart's. `null` means only that the platform could not
            resolve this chart's provenance on this request (see `ehrActive`);
            it never means the chart has no EHR.
          nullable: true
          example: modmed
        ehrPatientId:
          type: string
          description: >-
            The patient's EHR-native identifier in that system, so this listing
            self-identifies. It is read from the patient's own record, so it
            survives a failure to resolve the chart's instance — the
            partial-failure shape you are most likely to see is a populated
            `ehrPatientId` next to a `null` `ehrType`, and that pair means "we
            know which record this is, but could not confirm its EHR this time".
            `null` means the record has no EHR chart at all: a patient created
            directly in this platform rather than synced from an EHR, for which
            `POST /patients/{id}/documents/refresh` returns 400. Both null only
            when the record itself could not be read.
          nullable: true
          example: '35242114'
        ehrActive:
          type: boolean
          description: >-
            Whether this chart can still be re-listed against its source EHR by
            the platform itself (see the same field on the patient resource).
            `false` means `POST /patients/{id}/documents/refresh` cannot advance
            `listFetchedAt` — only a clinic user opening the chart in the
            dashboard with their own EHR session could — so treat what you see
            as frozen and look for the patient's live chart on another instance.
            Read this BEFORE concluding from a fresh `listFetchedAt` that a
            chart is up to date: a successful re-list of an abandoned chart
            returns nothing new, which is indistinguishable from a genuinely
            quiet chart unless you look here. It is a "not known to be live"
            signal, not proof of a migration — when `ehrType` is `null` the
            platform could not resolve provenance at all, and this is reported
            `false` because the safe reading of an unknown is to distrust the
            freshness, not because a sibling chart necessarily exists.
          example: true
        lastRefresh:
          description: >-
            The most recent API-requested refresh of this chart, whatever its
            outcome — the terminal signal to poll after `POST
            /patients/{id}/documents/refresh`. Scoped to API-originated
            refreshes on purpose: a nightly sweep or a biller's dashboard
            listing runs on its own clock and would otherwise mask the outcome
            of your own request. Whether the chart's data is fresh is
            `listFetchedAt`, which counts every listing whoever ran it. Absent
            when no refresh has ever been requested through the API.
          allOf:
            - $ref: '#/components/schemas/PatientDocumentRefreshStatus'
        listFetchedAt:
          type: string
          description: >-
            When the document LIST was last refreshed against the EHR. Null when
            it never has been — in which case an empty `documents` array means
            'not yet listed', not 'no documents'.
          nullable: true
          example: '2026-08-14T09:00:00.000Z'
        pagination:
          $ref: '#/components/schemas/PaginationInfoResponse'
      required:
        - documents
        - ehrType
        - ehrPatientId
        - ehrActive
        - listFetchedAt
        - pagination
    ExternalPatientDocumentResponse:
      type: object
      properties:
        id:
          type: string
          description: >-
            Document reference identifier. An opaque UUID on every version —
            unlike the top-level resources, sub-resource ids are not
            prefix-encoded from v3, because the one place that accepts them back
            (`POST /faxes/send`'s `documentIds`) takes them raw too. Treat it as
            an opaque string.
          example: 9c1f0f7a-2f4b-4f2e-8a1e-6b0f2d3c4a5b
        kind:
          type: string
          description: >-
            Best-effort classification derived from the EHR's own category and
            the document title. `other` means we could not classify it — NOT
            that it is unimportant. Always cross-check `sourceCategory`.
          enum:
            - insurance_card
            - identification
            - prior_auth
            - clinical
            - other
          example: insurance_card
        sourceCategory:
          type: string
          description: >-
            The EHR's own category for the document, verbatim (ModMed
            `firmCategoryTab.title`, the EZDerm DMS folder path). Slash-joined
            when the EHR nests categories. Null when the EHR reports none.
          nullable: true
          example: Insurance Card Front
        title:
          type: string
          description: Display title in the EHR
          example: Insurance Card Front
        filename:
          type: string
          description: Original filename when the EHR reports one distinct from the title
          nullable: true
          example: insurance_card_front.jpg
        mimeType:
          type: string
          description: MIME type
          nullable: true
          example: image/jpeg
        bytes:
          type: number
          description: Size in bytes
          nullable: true
          example: 184320
        createdAt:
          type: string
          description: When the document was created/uploaded in the EHR
          nullable: true
          example: '2026-02-27T15:04:05.000Z'
        updatedAt:
          type: string
          description: >-
            The newest thing that happened to this document — created in the
            EHR, last returned by a chart refresh, downloaded here, or removed
            from the chart. This is what `updatedSince` compares against. Always
            present: every document carries a last-seen stamp even when the EHR
            dated nothing else.
          example: '2026-08-14T10:15:00.000Z'
        downloaded:
          type: boolean
          description: >-
            True when the bytes are staged in this platform's storage and `url`
            is therefore populated. False means the document exists on the chart
            but has never been pulled from the EHR — pulling it needs a clinic
            user's own EHR session, which an API key does not have.
          example: true
        url:
          type: string
          description: Short-lived signed download URL. Null when `downloaded` is false.
          nullable: true
          example: https://storage.maxcare.ai/…?X-Amz-Signature=…
        expiresInSeconds:
          type: number
          description: Lifetime of `url` in seconds. Null when there is no URL.
          nullable: true
          example: 3600
        deletedFromEhrAt:
          type: string
          description: >-
            Set when the document has since disappeared from the EHR chart. Null
            while it is still there.
          nullable: true
          example: null
      required:
        - id
        - kind
        - sourceCategory
        - title
        - filename
        - mimeType
        - bytes
        - createdAt
        - updatedAt
        - downloaded
        - url
        - expiresInSeconds
        - deletedFromEhrAt
    PatientDocumentRefreshStatus:
      type: object
      properties:
        status:
          type: string
          description: '`queued` while the listing is running; then `completed` or `failed`.'
          enum:
            - queued
            - completed
            - failed
          example: completed
        requestedVia:
          type: string
          description: Who asked for it.
          enum:
            - api
            - sweep
            - dashboard
          example: api
        requestedAt:
          type: string
          description: When it was requested
          example: '2026-08-15T20:15:00.000Z'
        completedAt:
          type: string
          description: When it reached a terminal state. Null while `queued`.
          nullable: true
          example: '2026-08-15T20:15:07.000Z'
        errorKind:
          type: string
          description: >-
            Why it failed, as a stable marker — `no_connector` (the organization
            has no live EHR connector we may read charts through), `ehr_auth`
            (the connector's EHR session is not usable), `ehr_error`,
            `no_ehr_identity`, `not_found`, `dispatch_error`,
            `unexpected_error`. Null unless `status` is `failed`. Never an EHR
            message.
          nullable: true
          example: null
      required:
        - status
        - requestedVia
        - requestedAt
        - completedAt
        - errorKind
    PaginationInfoResponse:
      type: object
      properties:
        page:
          type: number
          description: Current page number
          example: 1
        pageSize:
          type: number
          description: Items per page
          example: 100
        totalCount:
          type: number
          description: Total number of items
          example: 250
        totalPages:
          type: number
          description: Total number of pages
          example: 3
      required:
        - page
        - pageSize
        - totalCount
        - totalPages
  securitySchemes:
    api-key:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Marketplace API key

````