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

# File a document on a patient's chart

> Multipart upload of one PDF, PNG or JPEG (up to 25 MB; larger is refused with 413) into the patient's chart in the EHR. Send exactly one of `category` or `type`. `category` (pathology, lab, prior_authorization, …) files the document where that category lives on the patient's EHR instance — see `GET /documents/categories`: ModMed the practice's matching category tab, EZDerm the Correspondences folder. A category the instance has no place for (or, on ModMed, a lab, pathology or imaging result while the practice's results log cannot be read) is still filed, on the chart uncategorized (EZDerm, which has no uncategorized folder, files it in Correspondences). `data.location` says where it landed, or is null when the document is on the chart uncategorized — no place for the category, or ModMed took the file but did not confirm the category; do not upload it again. `type: REFERRAL` is the original form, kept as it was: EZDerm files it in the Correspondences folder; ModMed files it as an attachment titled `title` in the practice's Referral category, or uncategorized when the practice has none. The declared content type is a hint only — the BYTES are sniffed, and anything else is rejected with 415 `unsupported_media_type`. The chart is re-listed right after the upload, so `documentId` is the id `GET /patients/{id}/documents` reports. `documentId: null` means that re-list failed, NOT the upload — the document is on the chart; do not upload it again. Send an `Idempotency-Key` header: a retry of the same file replays the original result for 24 hours, and a key reused for a different file is refused with 409. If the EHR does not confirm the upload the request fails with 409 `ehr_write_uncertain` — check the chart before uploading again. No copy of the bytes is kept on our side. Requires write:patient_documents.



## OpenAPI

````yaml /openapi-v4.json post /patients/{id}/documents
openapi: 3.0.0
info:
  title: Max AI Public API
  description: API for third-party marketplace apps
  version: '4.0'
  contact: {}
servers:
  - url: https://api.maxcare.ai/v4
security: []
tags: []
paths:
  /patients/{id}/documents:
    post:
      tags:
        - Patients
      summary: File a document on a patient's chart
      description: >-
        Multipart upload of one PDF, PNG or JPEG (up to 25 MB; larger is refused
        with 413) into the patient's chart in the EHR. Send exactly one of
        `category` or `type`. `category` (pathology, lab, prior_authorization,
        …) files the document where that category lives on the patient's EHR
        instance — see `GET /documents/categories`: ModMed the practice's
        matching category tab, EZDerm the Correspondences folder. A category the
        instance has no place for (or, on ModMed, a lab, pathology or imaging
        result while the practice's results log cannot be read) is still filed,
        on the chart uncategorized (EZDerm, which has no uncategorized folder,
        files it in Correspondences). `data.location` says where it landed, or
        is null when the document is on the chart uncategorized — no place for
        the category, or ModMed took the file but did not confirm the category;
        do not upload it again. `type: REFERRAL` is the original form, kept as
        it was: EZDerm files it in the Correspondences folder; ModMed files it
        as an attachment titled `title` in the practice's Referral category, or
        uncategorized when the practice has none. The declared content type is a
        hint only — the BYTES are sniffed, and anything else is rejected with
        415 `unsupported_media_type`. The chart is re-listed right after the
        upload, so `documentId` is the id `GET /patients/{id}/documents`
        reports. `documentId: null` means that re-list failed, NOT the upload —
        the document is on the chart; do not upload it again. Send an
        `Idempotency-Key` header: a retry of the same file replays the original
        result for 24 hours, and a key reused for a different file is refused
        with 409. If the EHR does not confirm the upload the request fails with
        409 `ehr_write_uncertain` — check the chart before uploading again. No
        copy of the bytes is kept on our side. Requires write:patient_documents.
      operationId: PatientsPublicController_createPatientDocument
      parameters:
        - name: id
          required: true
          in: path
          description: Patient ID
          schema:
            type: string
        - name: idempotency-key
          required: false
          in: header
          description: Client-generated key protecting retries for 24 hours
          schema:
            type: string
        - name: X-Organization-Id
          in: header
          required: true
          schema:
            type: string
          description: Target clinic organization ID
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - file
              properties:
                file:
                  type: string
                  format: binary
                  description: The document (PDF, PNG or JPEG)
                category:
                  type: string
                  enum:
                    - referral
                    - pathology
                    - lab
                    - imaging
                    - prior_authorization
                    - medical_records
                    - records_request
                    - correspondence
                    - prescription
                    - forms
                    - insurance
                    - billing
                    - audit
                    - disclosure
                  description: >-
                    What the document is; decides where it is filed. Send this
                    or `type`.
                type:
                  type: string
                  enum:
                    - REFERRAL
                  description: 'The original form of `category: referral`'
                title:
                  type: string
                  maxLength: 200
                  description: Title shown on the chart
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/CreatePatientDocumentSuccessResponse'
        '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'
        '409':
          description: Resource conflict (e.g. editing a signed note)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiConflictResponse'
        '413':
          description: Request body or uploaded file too large
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiPayloadTooLargeResponse'
        '415':
          description: Unsupported media type
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicApiUnsupportedMediaTypeResponse'
        '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:
    CreatePatientDocumentSuccessResponse:
      type: object
      properties:
        code:
          type: string
          description: Response code
          example: success
        data:
          $ref: '#/components/schemas/CreatePatientDocumentData'
      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
    PublicApiConflictResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: conflict
        message:
          type: string
          description: Human-readable error message
          example: Cannot edit a signed note
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiPayloadTooLargeResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: payload_too_large
        message:
          type: string
          description: Human-readable error message
          example: File too large
        trace_id:
          type: string
          description: Trace ID for debugging
          example: 550e8400-e29b-41d4-a716-446655440000
      required:
        - code
        - message
        - trace_id
    PublicApiUnsupportedMediaTypeResponse:
      type: object
      properties:
        code:
          type: string
          description: Error code
          example: unsupported_media_type
        message:
          type: string
          description: Human-readable error message
          example: The uploaded file is not a PNG, JPEG, WEBP or HEIC image
        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
    CreatePatientDocumentData:
      type: object
      properties:
        patientId:
          type: string
          description: Patient the document was filed on
          example: pat_c56103bcd39c46d39f3138dd2b5e05f6
        documentId:
          type: string
          nullable: true
          description: >-
            The document's id in `GET /patients/{id}/documents`. Null when the
            chart could not be re-listed right after the upload — the document
            IS on the chart; it appears in the list after `POST
            /patients/{id}/documents/refresh` or the nightly sweep. Do not
            re-upload.
          example: 3f1c2a9e-7b1d-4c55-9a0e-2d4b8c1e6f70
        ehrDocumentId:
          type: string
          description: The EHR's own id for the file
          example: '201269302'
        ref:
          type: string
          nullable: true
          description: >-
            The document's signed `ref`, accepted as `documentRef` by `POST
            /v4/ehr/patients/{id}/insurances/{policyRef}/prior-authorizations`.
            Null only on a replay of an upload made before refs existed.
          example: ehr_eyJp….c2ln
        type:
          type: string
          enum:
            - REFERRAL
          nullable: true
          description: >-
            `REFERRAL` on a legacy `type` upload; null when the upload named a
            `category`.
          example: null
        category:
          type: string
          enum:
            - referral
            - pathology
            - lab
            - imaging
            - prior_authorization
            - medical_records
            - records_request
            - correspondence
            - prescription
            - forms
            - insurance
            - billing
            - audit
            - disclosure
          nullable: true
          description: >-
            The `category` the upload named; null on a legacy `type: REFERRAL`
            upload.
          example: pathology
        location:
          nullable: true
          description: >-
            Where the EHR filed it. Null on a legacy upload; when the category
            has no place on the instance (on ModMed also a lab, pathology or
            imaging result while the results log cannot be read); and when a
            ModMed upload landed on the chart but the EHR did not confirm the
            category. The document IS on the chart, uncategorized (EZDerm, which
            has no uncategorized folder: in Correspondences); do not re-upload.
          allOf:
            - $ref: '#/components/schemas/DocumentLocationResponse'
      required:
        - patientId
        - documentId
        - ehrDocumentId
        - ref
        - type
        - category
        - location
    DocumentLocationResponse:
      type: object
      properties:
        id:
          type: string
          description: The EHR's id for it (ModMed category tab id, EZDerm folder type)
          example: '333500'
        title:
          type: string
          description: Name staff see in the EHR
          example: Pathology
        resultsLog:
          type: boolean
          description: >-
            ModMed: the tab feeds the Results Management log, where providers
            review and sign results. Lab, pathology and imaging uploads prefer
            such a tab. Routing to a specific provider is not set by the upload;
            assign a provider review task (POST /tasks) for that. Always false
            on EZDerm.
          example: true
      required:
        - id
        - title
        - resultsLog
  securitySchemes:
    api-key:
      scheme: bearer
      bearerFormat: JWT
      type: http
      description: Marketplace API key

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.