openapi: 3.1.0
info:
  title: MindBill Partner API
  version: 2.0.0
  description: |
    One bill is the unit of integration. Send the values that belong on the claim,
    attach the payer packet explicitly, and retain the returned bill ID. MindBill owns
    submission, status, EORs, payments, denials, reviews, and resubmission.

    API keys belong only on your server. Browser integrations use a short-lived,
    origin-bound session scoped to one bill. Sandbox accepts synthetic data only.
servers:
  - url: https://app.mindbill.org/partner/v2
security:
  - bearerAuth: []
tags:
  - name: Bills
  - name: Documents
  - name: Lifecycle
  - name: Events
  - name: Browser sessions
paths:
  /bills:
    get:
      tags: [Bills]
      operationId: listBills
      summary: List bills
      description: Find bills by your stable IDs or lifecycle state. Results use cursor pagination.
      parameters:
        - { name: externalId, in: query, description: Your stable bill or work-item ID., schema: { type: string } }
        - { name: patientExternalId, in: query, description: Your stable patient ID., schema: { type: string } }
        - { name: claimExternalId, in: query, description: Your stable claim or injury ID., schema: { type: string } }
        - { name: state, in: query, description: MindBill lifecycle state., schema: { $ref: '#/components/schemas/BillState' } }
        - { name: cursor, in: query, description: Opaque cursor returned by the previous page., schema: { type: string } }
        - { name: limit, in: query, description: Page size., schema: { type: integer, minimum: 1, maximum: 100, default: 25 } }
      responses:
        '200':
          description: A page of bills.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillPage' }
        default: { $ref: '#/components/responses/Problem' }
    post:
      tags: [Bills]
      operationId: createBill
      summary: Create a bill
      description: |
        Create one mutable bill snapshot from data you already know. Profiles are not
        required. Store the returned bill ID and use it for every later operation.
        `med_legal` is the enabled billing mode. `professional` is not enabled yet and
        currently returns an explicit validation error.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BillCreate' }
      responses:
        '201':
          description: Bill created.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Bill' }
        '200':
          description: Idempotent replay of the original create.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Bill' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}:
    parameters:
      - $ref: '#/components/parameters/BillId'
    get:
      tags: [Bills]
      operationId: getBill
      summary: Get a bill
      description: Read the authoritative bill snapshot, documents, lines, state, and amounts.
      responses:
        '200':
          description: Bill snapshot.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Bill' }
        default: { $ref: '#/components/responses/Problem' }
    patch:
      tags: [Bills]
      operationId: updateBill
      summary: Update a bill
      description: Patch editable claim values before submission or while correcting a rejected bill.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BillUpdate' }
      responses:
        '200':
          description: Updated bill.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/Bill' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/documents:
    parameters:
      - $ref: '#/components/parameters/BillId'
    get:
      tags: [Documents]
      operationId: listBillDocuments
      summary: List payer-packet documents
      description: Review exactly which documents are attached to the payer billing packet.
      responses:
        '200':
          description: Explicit payer-packet documents.
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data: { type: array, items: { $ref: '#/components/schemas/Document' } }
        default: { $ref: '#/components/responses/Problem' }
    post:
      tags: [Documents]
      operationId: uploadBillDocument
      summary: Attach a PDF
      description: |
        Add one PDF intentionally. Medical records are never attached unless the partner
        or user explicitly adds them. The payer packet is distinct from any attorney
        report-service packet.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required: [file, documentType]
              properties:
                file: { type: string, format: binary, description: PDF up to 25 MB. }
                documentType: { $ref: '#/components/schemas/DocumentType' }
                externalId: { type: string, description: Your stable document ID. }
                description: { type: string, description: Optional user-facing label. }
      responses:
        '201':
          description: Document attached.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/DocumentEnvelope' }
        '200':
          description: Idempotent replay of the original upload.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/DocumentEnvelope' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/documents/{documentId}:
    parameters:
      - $ref: '#/components/parameters/BillId'
      - $ref: '#/components/parameters/DocumentId'
    get:
      tags: [Documents]
      operationId: getBillDocument
      summary: Download a PDF
      description: Download one authorized payer-packet document.
      responses:
        '200':
          description: PDF bytes.
          content:
            application/pdf:
              schema: { type: string, format: binary }
        default: { $ref: '#/components/responses/Problem' }
    delete:
      tags: [Documents]
      operationId: deleteBillDocument
      summary: Remove a PDF
      description: Remove a document before the next submission.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '204': { description: Document removed. }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/submissions:
    post:
      tags: [Lifecycle]
      operationId: submitBill
      summary: Submit a bill
      description: Atomically validate and submit the current bill snapshot and payer packet.
      parameters:
        - $ref: '#/components/parameters/BillId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                route: { $ref: '#/components/schemas/DeliveryRoute' }
      responses:
        '202':
          description: Sandbox submission accepted.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/SubmissionResult' }
        '200':
          description: Live submission or idempotent replay accepted.
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/status:
    get:
      tags: [Lifecycle]
      operationId: getBillStatus
      summary: Get bill status
      description: Read the compact, authoritative lifecycle and aging surface.
      parameters:
        - $ref: '#/components/parameters/BillId'
      responses:
        '200':
          description: Current lifecycle status.
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data: { $ref: '#/components/schemas/BillStatus' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/eor:
    get:
      tags: [Lifecycle]
      operationId: getBillEor
      summary: Get EOR and payment details
      description: Read parsed EOR line items, posted payments, balances, and original EOR PDFs when available.
      parameters:
        - $ref: '#/components/parameters/BillId'
      responses:
        '200':
          description: EOR and remittance data.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/EorEnvelope' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/actions:
    post:
      tags: [Lifecycle]
      operationId: performBillAction
      summary: Perform the next bill action
      description: Close a bill, post a payment, submit Second Bill Review, or start a correction/resubmission.
      parameters:
        - $ref: '#/components/parameters/BillId'
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              oneOf:
                - $ref: '#/components/schemas/CloseAction'
                - $ref: '#/components/schemas/PostPaymentAction'
                - $ref: '#/components/schemas/SecondReviewAction'
                - $ref: '#/components/schemas/StartCorrectionAction'
              discriminator: { propertyName: action }
      responses:
        '200':
          description: Action completed.
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
        '201':
          description: Replacement bill created for correction and resubmission.
          content:
            application/json:
              schema: { type: object, additionalProperties: true }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/reviews:
    parameters:
      - $ref: '#/components/parameters/BillId'
    get:
      tags: [Lifecycle]
      operationId: listBillReviews
      summary: List bill reviews
      description: List Second Bill Review and IBR records linked to the original bill.
      responses:
        '200':
          description: Reviews.
          content:
            application/json:
              schema:
                type: object
                required: [data]
                properties:
                  data: { type: array, items: { $ref: '#/components/schemas/BillReview' } }
        default: { $ref: '#/components/responses/Problem' }
    post:
      tags: [Lifecycle]
      operationId: createBillReview
      summary: Create a bill review
      description: Create a review draft with the reason, disputed amount, and explicit supporting attachments.
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema: { $ref: '#/components/schemas/BillReviewCreate' }
      responses:
        '201':
          description: Review created.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillReviewEnvelope' }
        '200':
          description: Idempotent replay of the original create.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillReviewEnvelope' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/reviews/{reviewId}:
    get:
      tags: [Lifecycle]
      operationId: getBillReview
      summary: Get a bill review
      description: Read one review and its selected attachment IDs.
      parameters:
        - $ref: '#/components/parameters/BillId'
        - $ref: '#/components/parameters/ReviewId'
      responses:
        '200':
          description: Review.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillReviewEnvelope' }
        default: { $ref: '#/components/responses/Problem' }
  /bills/{billId}/reviews/{reviewId}/submissions:
    post:
      tags: [Lifecycle]
      operationId: submitBillReview
      summary: Submit a bill review
      description: Submit the review draft with its selected supporting documents.
      parameters:
        - $ref: '#/components/parameters/BillId'
        - $ref: '#/components/parameters/ReviewId'
        - $ref: '#/components/parameters/IdempotencyKey'
      responses:
        '202':
          description: Review submission accepted.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillReviewEnvelope' }
        '200':
          description: Review was already submitted or this is an idempotent replay.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BillReviewEnvelope' }
        default: { $ref: '#/components/responses/Problem' }
  /events:
    get:
      tags: [Events]
      operationId: listEvents
      summary: List lifecycle events
      description: Recover missed webhook events in sequence order. Persist the returned cursor.
      parameters:
        - { name: cursor, in: query, description: Opaque cursor returned by the previous page., schema: { type: string } }
        - { name: limit, in: query, description: Page size., schema: { type: integer, minimum: 1, maximum: 100, default: 50 } }
      responses:
        '200':
          description: Event page.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/EventPage' }
        default: { $ref: '#/components/responses/Problem' }
  /webhook-deliveries:
    get:
      tags: [Events]
      operationId: listWebhookDeliveries
      summary: List webhook deliveries
      description: Inspect delivery attempts for operational reconciliation.
      parameters:
        - { name: cursor, in: query, description: Opaque cursor returned by the previous page., schema: { type: string } }
        - { name: limit, in: query, description: Page size., schema: { type: integer, minimum: 1, maximum: 100, default: 50 } }
      responses:
        '200':
          description: Delivery page.
          content:
            application/json:
              schema:
                type: object
                required: [deliveries]
                properties:
                  deliveries: { type: array, items: { $ref: '#/components/schemas/WebhookDelivery' } }
        default: { $ref: '#/components/responses/Problem' }
  /browser-sessions:
    post:
      tags: [Browser sessions]
      operationId: createBrowserSession
      summary: Mint an origin-bound browser session
      description: |
        Exchange the server-only API key for a short-lived token. Bill review and timeline
        sessions are scoped to one bill. The browser can then call MindBill directly.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [component, allowedOrigin]
              properties:
                component: { $ref: '#/components/schemas/BrowserComponent' }
                billId: { type: string, description: Required for bill-review and bill-timeline. }
                allowedOrigin: { type: string, format: uri, description: Exact HTTPS browser origin with no path. }
                expiresIn: { type: integer, minimum: 60, maximum: 3600, default: 900, description: Token lifetime in seconds. }
      responses:
        '201':
          description: Short-lived browser session.
          content:
            application/json:
              schema: { $ref: '#/components/schemas/BrowserSession' }
        default: { $ref: '#/components/responses/Problem' }
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: Partner API key
  parameters:
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: true
      description: Stable UUID for one logical write. Reuse it only when retrying the identical request.
      schema: { type: string, minLength: 8, maxLength: 128 }
    BillId: { name: billId, in: path, required: true, description: MindBill bill ID., schema: { type: string } }
    DocumentId: { name: documentId, in: path, required: true, description: MindBill document ID., schema: { type: string } }
    ReviewId: { name: reviewId, in: path, required: true, description: MindBill review ID., schema: { type: string } }
  responses:
    Problem:
      description: Request failed.
      content:
        application/problem+json:
          schema: { $ref: '#/components/schemas/Problem' }
  schemas:
    Problem:
      type: object
      required: [type, title, status, code]
      properties:
        type: { type: string, format: uri, description: Stable problem type URI. }
        title: { type: string, description: Short error summary. }
        status: { type: integer, description: HTTP status. }
        code: { type: string, description: Stable machine-readable error code. }
        detail: { type: string, description: Human-readable context. }
        errors: { type: array, items: { type: object, additionalProperties: true }, description: Field-level validation details. }
    BillState:
      type: string
      enum: [draft, scrub_failed, submitted, accepted, rejected, denied, partially_paid, paid, second_review, lien, ibr, closed, written_off]
    BillingMode:
      type: string
      enum: [med_legal, professional]
      default: med_legal
      description: Professional is reserved and not enabled in the public API yet.
    Address:
      type: object
      additionalProperties: false
      required: [line1, city, state, postalCode]
      properties:
        line1: { type: string, description: Street and suite as printed on the claim. }
        city: { type: string, description: City. }
        state: { type: string, pattern: '^[A-Z]{2}$', description: Two-letter state code. }
        postalCode: { type: string, description: ZIP or postal code. }
    PatientInput:
      type: object
      additionalProperties: false
      required: [firstName, lastName, address]
      properties:
        id: { type: string, description: Optional MindBill patient ID. Do not send with externalId. }
        externalId: { type: string, description: Your stable patient ID. Do not send with id. }
        firstName: { type: string, description: Patient first name. }
        middleName: { type: string, description: Patient middle name. }
        lastName: { type: string, description: Patient last name. }
        dateOfBirth: { type: string, format: date, description: Patient date of birth. }
        ssn: { type: string, description: SSN when required for the claim. }
        gender: { type: string, enum: [M, F, X], description: Claim-form gender code. }
        phone: { type: string, description: Patient phone. }
        address: { $ref: '#/components/schemas/Address' }
    ClaimsAdministrator:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        id: { type: string, description: MindBill payer-directory ID. }
        name: { type: string, description: Carrier or claims-administrator name for directory matching. }
    ClaimInput:
      type: object
      additionalProperties: false
      required: [claimNumber]
      properties:
        id: { type: string, description: Optional MindBill claim ID. Do not send with externalId. }
        externalId: { type: string, description: Your stable claim or injury ID. Do not send with id. }
        claimNumber: { type: string, description: Payer claim number. }
        adjNumber: { type: string, pattern: '^ADJ[0-9]{7,}$', description: California EAMS ADJ number when present. }
        employer: { type: string, description: Employer name. }
        dateOfInjury: { type: string, format: date, description: Date of injury or cumulative-trauma end date. }
        injuryState: { type: string, pattern: '^[A-Z]{2}$', description: Two-letter injury state. }
        description: { type: string, description: Injury description. }
        claimsAdministrator: { $ref: '#/components/schemas/ClaimsAdministrator' }
    ServiceInput:
      type: object
      additionalProperties: false
      properties:
        date: { type: string, format: date, description: Optional while the bill is a draft; required before submission. }
        endDate: { type: [string, 'null'], format: date, description: Optional service-period end date for a genuinely ranged service. }
        authorizationNumber: { type: [string, 'null'], description: Optional prior authorization number. }
    BillingProviderInput:
      type: object
      additionalProperties: false
      properties:
        name: { type: string, description: Payee or practice name. }
        taxId: { type: string, description: Billing tax ID. }
        npi: { type: string, description: Billing NPI. For a solo practice this may equal the clinician NPI. }
        phone: { type: string, description: Billing phone. }
        address: { $ref: '#/components/schemas/Address' }
    RenderingProviderInput:
      type: object
      additionalProperties: false
      properties:
        name: { type: string, description: Rendering clinician name. }
        specialty: { type: string, description: Clinician specialty. }
        npi: { type: string, description: Individual rendering NPI. }
        taxonomy: { type: string, description: Provider taxonomy code. }
        licenseNumber: { type: string, description: Professional license number. }
        licenseState: { type: string, pattern: '^[A-Z]{2}$', description: Two-letter license state. }
        isQme: { type: boolean, description: Qualified Medical Evaluator flag used by med-legal fee logic. }
        isAme: { type: boolean, description: Agreed Medical Evaluator flag used by med-legal fee logic. }
    ServiceLocationInput:
      type: object
      additionalProperties: false
      properties:
        name: { type: string, description: Location label. }
        address: { $ref: '#/components/schemas/Address' }
        placeOfServiceCode: { type: string, pattern: '^[0-9]{2}$', description: CMS place-of-service code. }
    ServiceLineInput:
      type: object
      additionalProperties: false
      required: [code]
      properties:
        id: { type: string, description: Existing line ID when editing. }
        code: { type: string, description: Procedure code such as ML201. }
        modifiers: { type: array, maxItems: 8, items: { type: string, maxLength: 4 }, default: [], description: Procedure modifiers without hyphens. }
        units: { type: integer, minimum: 1, maximum: 10000, default: 1, description: Billable units. }
    BillCreate:
      type: object
      additionalProperties: false
      required: [patient, claim, service]
      properties:
        externalId: { type: string, description: Your stable bill or work-item ID. }
        billingMode: { $ref: '#/components/schemas/BillingMode' }
        patient: { $ref: '#/components/schemas/PatientInput' }
        claim: { $ref: '#/components/schemas/ClaimInput' }
        service: { $ref: '#/components/schemas/ServiceInput' }
        billingProvider: { $ref: '#/components/schemas/BillingProviderInput' }
        renderingProvider: { $ref: '#/components/schemas/RenderingProviderInput' }
        serviceLocation: { $ref: '#/components/schemas/ServiceLocationInput' }
        diagnoses: { type: array, items: { type: string }, default: [], description: ICD-10 diagnosis codes. }
        serviceLines: { type: array, maxItems: 50, items: { $ref: '#/components/schemas/ServiceLineInput' }, default: [], description: Known lines; the review UI can complete missing lines. }
    BillUpdate:
      type: object
      additionalProperties: false
      minProperties: 1
      description: Any subset of editable bill snapshot fields. Patient address may also be partial.
      properties:
        patient: { type: object, additionalProperties: true, description: Partial patient snapshot. }
        claim: { type: object, additionalProperties: true, description: Partial claim snapshot. }
        service: { type: object, additionalProperties: true, description: Partial service snapshot. }
        billingProvider: { $ref: '#/components/schemas/BillingProviderInput' }
        renderingProvider: { $ref: '#/components/schemas/RenderingProviderInput' }
        serviceLocation: { $ref: '#/components/schemas/ServiceLocationInput' }
        diagnoses: { type: array, items: { type: string }, description: Replacement ICD-10 list. }
        serviceLines: { type: array, minItems: 1, maxItems: 50, items: { $ref: '#/components/schemas/ServiceLineInput' }, description: Replacement service-line list. }
    Patient:
      allOf:
        - $ref: '#/components/schemas/PatientInput'
    Claim:
      allOf:
        - $ref: '#/components/schemas/ClaimInput'
        - type: object
          properties:
            diagnoses: { type: array, items: { type: string }, description: ICD-10 codes frozen on this bill. }
    BillingProvider:
      type: [object, 'null']
      additionalProperties: false
      properties:
        name: { type: string }
        taxId: { type: string }
        npi: { type: string }
        phone: { type: string }
        address: { $ref: '#/components/schemas/Address' }
    RenderingProvider:
      type: [object, 'null']
      additionalProperties: false
      properties:
        name: { type: string }
        specialty: { type: string }
        npi: { type: string }
        taxonomy: { type: string }
        licenseNumber: { type: string }
        licenseState: { type: string }
        isQme: { type: boolean }
        isAme: { type: boolean }
    ServiceLocation:
      type: [object, 'null']
      additionalProperties: false
      properties:
        name: { type: string }
        address: { $ref: '#/components/schemas/Address' }
        placeOfServiceCode: { type: string }
    ServiceLine:
      type: object
      required: [id, code, modifiers, units, charge, feeSchedule]
      properties:
        id: { type: string }
        code: { type: string }
        modifiers: { type: array, items: { type: string } }
        units: { type: integer }
        charge: { type: number, description: Current line charge in dollars. }
        feeSchedule: { type: number, description: Current allowed fee-schedule amount in dollars. }
    DocumentType:
      type: string
      enum: [final_report, letter_of_attestation, proof_of_service, form_122, return_to_work_voucher, w9, medical_records, appeal, other]
    Document:
      type: object
      required: [id, filename, documentType, source, addedAt, contentUrl]
      properties:
        id: { type: string }
        externalId: { type: [string, 'null'] }
        filename: { type: string }
        description: { type: [string, 'null'] }
        documentType: { $ref: '#/components/schemas/DocumentType' }
        reportType: { type: [string, 'null'] }
        reportTypeCode: { type: [string, 'null'] }
        source: { type: string }
        addedAt: { type: string, format: date-time }
        contentUrl: { type: string, format: uri }
    DocumentEnvelope:
      type: object
      required: [data]
      properties:
        data: { $ref: '#/components/schemas/Document' }
    Amounts:
      type: object
      required: [charged, paid, balance]
      properties:
        charged: { type: number, description: Total charged in dollars. }
        paid: { type: number, description: Total posted payments in dollars. }
        balance: { type: number, description: Current balance in dollars. }
    Bill:
      type: object
      required: [id, state, billingMode, patient, claim, service, serviceLines, documents, amounts]
      properties:
        id: { type: string, description: Stable MindBill bill ID. }
        externalId: { type: [string, 'null'], description: Your stable bill or work-item ID. }
        state: { $ref: '#/components/schemas/BillState' }
        billingMode: { const: med_legal }
        billNumber: { type: [integer, 'null'] }
        patient: { $ref: '#/components/schemas/Patient' }
        claim: { $ref: '#/components/schemas/Claim' }
        service: { $ref: '#/components/schemas/ServiceInput' }
        billingProvider: { $ref: '#/components/schemas/BillingProvider' }
        renderingProvider: { $ref: '#/components/schemas/RenderingProvider' }
        serviceLocation: { $ref: '#/components/schemas/ServiceLocation' }
        serviceLines: { type: array, items: { $ref: '#/components/schemas/ServiceLine' } }
        documents: { type: array, items: { $ref: '#/components/schemas/Document' } }
        amounts: { $ref: '#/components/schemas/Amounts' }
    BillPage:
      type: object
      required: [data]
      properties:
        data: { type: array, items: { $ref: '#/components/schemas/Bill' } }
        nextCursor: { type: [string, 'null'] }
    DeliveryRoute:
      type: string
      enum: [ebill, fax, mail, email]
      default: ebill
    SubmissionResult:
      type: object
      required: [ok, sandbox, livemode, billId, controlNumber, state, status]
      properties:
        ok: { const: true }
        sandbox: { const: true }
        livemode: { const: false }
        billId: { type: string }
        controlNumber: { type: string }
        state: { const: submitted }
        status: { const: submitted }
    BillStatus:
      type: object
      required: [billId, state, totalCharge, totalPaid, balanceDue]
      properties:
        billId: { type: string }
        externalId: { type: [string, 'null'] }
        state: { $ref: '#/components/schemas/BillState' }
        nativeStatus: { type: [string, 'null'] }
        totalCharge: { type: number }
        totalPaid: { type: number }
        balanceDue: { type: number }
        lastEventId: { type: [string, 'null'] }
        updatedAt: { type: [string, 'null'], format: date-time }
    CloseAction:
      type: object
      additionalProperties: false
      required: [action, reason]
      properties:
        action: { const: close }
        reason: { type: string, minLength: 1 }
    PostPaymentAction:
      type: object
      additionalProperties: false
      required: [action, amount, method, depositDate]
      properties:
        action: { const: post_payment }
        amount: { type: number, exclusiveMinimum: 0, description: Payment amount in dollars. }
        method: { type: string, enum: [check, eft] }
        checkNumber: { type: string, default: '' }
        depositDate: { type: string, format: date }
        note: { type: string }
    SecondReviewAction:
      type: object
      additionalProperties: false
      required: [action, reason, payerClaimControlNumber]
      properties:
        action: { const: second_review }
        reason: { type: string, minLength: 1 }
        payerClaimControlNumber: { type: string, minLength: 1 }
        disputedAmount: { type: number, minimum: 0 }
        attachmentIds: { type: array, items: { type: string }, default: [] }
        route: { $ref: '#/components/schemas/DeliveryRoute' }
    StartCorrectionAction:
      type: object
      additionalProperties: false
      required: [action]
      properties:
        action: { const: start_correction }
    BillReviewCreate:
      type: object
      additionalProperties: false
      required: [type, reason]
      properties:
        type: { type: string, enum: [second_review, independent_bill_review] }
        externalId: { type: string, description: Your stable review ID. }
        reason: { type: string, minLength: 1 }
        disputedAmount: { type: number, minimum: 0 }
        payerClaimControlNumber: { type: string }
        attachmentIds: { type: array, items: { type: string }, default: [] }
    BillReview:
      type: object
      required: [id, billId, originalBillId, type, state, reason, attachmentIds, createdAt, updatedAt]
      properties:
        id: { type: string }
        billId: { type: string }
        originalBillId: { type: string }
        externalId: { type: [string, 'null'] }
        type: { type: string, enum: [second_review, independent_bill_review] }
        state: { type: string, enum: [draft, submitted] }
        reason: { type: string }
        disputedAmount: { type: [number, 'null'] }
        payerClaimControlNumber: { type: [string, 'null'] }
        attachmentIds: { type: array, items: { type: string } }
        submittedAt: { type: [string, 'null'], format: date-time }
        createdAt: { type: string, format: date-time }
        updatedAt: { type: string, format: date-time }
    BillReviewEnvelope:
      type: object
      required: [data]
      properties:
        data: { $ref: '#/components/schemas/BillReview' }
    EorEnvelope:
      type: object
      required: [data]
      properties:
        data:
          type: object
          required: [billId, reportedPaid, totalPaid, balanceDue, payments, lineItems, documents]
          properties:
            billId: { type: string }
            reportedPaid: { type: number }
            totalPaid: { type: number }
            balanceDue: { type: number }
            payment: { type: [object, 'null'], additionalProperties: true }
            payments: { type: array, items: { type: object, additionalProperties: true } }
            lineItems:
              type: array
              items:
                type: object
                required: [id, code, paid, allowedAmount, adjustmentAmount, patientResponsibility, reasonCodes]
                properties:
                  id: { type: string }
                  code: { type: string }
                  paid: { type: number }
                  allowedAmount: { type: number }
                  adjustmentAmount: { type: number }
                  patientResponsibility: { type: number }
                  reasonCodes: { type: array, items: { type: string } }
            documents:
              type: array
              items:
                type: object
                required: [id, filename, addedAt, contentUrl]
                properties:
                  id: { type: string }
                  filename: { type: string }
                  description: { type: [string, 'null'] }
                  addedAt: { type: string, format: date-time }
                  contentUrl: { type: string, format: uri }
    EventPage:
      type: object
      required: [events]
      properties:
        events:
          type: array
          items:
            type: object
            required: [id, sequence, type, apiVersion, createdAt, data]
            properties:
              id: { type: string }
              sequence: { type: string, pattern: '^[0-9]+$' }
              type: { type: string }
              apiVersion: { type: string }
              createdAt: { type: string, format: date-time }
              data: { type: object, additionalProperties: true }
        nextCursor: { type: [string, 'null'] }
    WebhookDelivery:
      type: object
      required: [id, eventId, sequence, eventType, status, attemptCount, createdAt]
      properties:
        id: { type: string }
        eventId: { type: string }
        sequence: { type: string, pattern: '^[0-9]+$' }
        eventType: { type: string }
        status: { type: string }
        attemptCount: { type: integer }
        responseStatus: { type: [integer, 'null'] }
        nextAttemptAt: { type: [string, 'null'], format: date-time }
        deliveredAt: { type: [string, 'null'], format: date-time }
        createdAt: { type: string, format: date-time }
    BrowserComponent:
      type: string
      enum: [bill-review, bill-timeline]
    BrowserSession:
      type: object
      required: [sessionId, component, token, embedUrl, expiresAt]
      properties:
        sessionId: { type: string }
        component: { $ref: '#/components/schemas/BrowserComponent' }
        token: { type: string, description: Short-lived browser credential. }
        embedUrl: { type: string, format: uri }
        expiresAt: { type: string, format: date-time }
        mindBillUrl: { type: string, format: uri }
