openapi: 3.1.0
info:
  title: LendEasy Public API
  version: 1.0.0
  summary: One public contract for the servicing control plane and optional lending core.
  description: The target LendEasy v1 contract for U.S. consumer installment lending, BNPL, receivables-based merchant
    advances, governed servicing, and bring-your-own-core integrations. All amounts are decimal strings and all
    timestamps are RFC 3339.
  contact:
    name: LendEasy Developer Experience
    url: https://docs.lendeasy.ai
servers:
  - url: https://sandbox.api.lendeasy.ai
    description: Sandbox with simulated money rails.
  - url: https://api.lendeasy.ai
    description: Production.
tags:
  - name: Cases
    x-surface: servicing
    description: Durable borrower and merchant matters, workflow state, timelines, escalation, and closure.
  - name: Tasks
    x-surface: servicing
    description: Queue work, reservation, assignment, execution, and completion.
  - name: Interactions
    x-surface: servicing
    description: Inbound and outbound communications across voice, email, SMS, secure message, and mail.
  - name: Compliance decisions
    x-surface: servicing
    description: Execution-time, explainable policy decisions grounded in fresh facts.
  - name: Promises
    x-surface: servicing
    description: Borrower payment commitments, approval, revision, suppression, and evaluation.
  - name: Action requests
    x-surface: servicing
    description: Case-linked, typed requests to change an authoritative system of record.
  - name: Case documents
    x-surface: servicing
    description: Register, classify, review, and securely retrieve case evidence.
  - name: Verification
    x-surface: servicing
    description: Identity and authority verification sessions with attempt controls.
  - name: AI sessions
    x-surface: servicing
    description: Governed AI work sessions, proposed output, review, and termination.
  - name: Privacy requests
    x-surface: servicing
    description: Access, deletion, correction, and portability workflows.
  - name: Core bindings
    x-surface: servicing
    description: Bring-your-own-core capabilities, facts, actions, identity mappings, and reconciliation.
  - name: Webhooks
    x-surface: servicing
    description: Tenant-owned event subscriptions, signing-secret rotation, tests, and delivery history.
  - name: Customers
    x-surface: lms
    description: Customer aggregates with a closed INDIVIDUAL or CORPORATE profile, masked ordinary reads, audited sensitive
      reads, and an append-only history ledger.
  - name: Search
    x-surface: lms
    description: Permission-aware exact and prefix search across customers and loans.
  - name: Addresses
    x-surface: lms
    description: Typed customer addresses with focused mutations and history.
  - name: Contact points
    x-surface: lms
    description: Email and phone contact points with explicit texting permission and trusted-integration verification.
  - name: Customer identifiers
    x-surface: lms
    description: Government identifiers stored normalized, masked on ordinary reads, revealed only through audited sensitive routes.
  - name: Forms
    x-surface: lms
    description: Administered form definitions and typed customer and loan form entries with derived per-form permissions.
  - name: Notes
    x-surface: lms
    description: Customer and loan notes with immutable revisions, links, and permanent redaction.
  - name: Documents
    x-surface: lms
    description: Customer and loan documents with virus scanning, checksum-verified downloads, links, and history.
  - name: Consents
    x-surface: lms
    description: "The closed consent catalog: grants with capture evidence and immutable revocation."
  - name: Payment instruments
    x-surface: lms
    description: Processor-tokenized bank and card instruments with masked reads and provider-event verification.
  - name: Loan parties
    x-surface: lms
    description: Co-borrower, guarantor, and authorized-party relationships with explicit authority scopes.
  - name: External parties
    x-surface: lms
    description: Merchants and other verified counterparties eligible to receive funding.
  - name: Loan products
    x-surface: lms
    description: Progressive loan products carrying LendEasy APR, statement, and overpayment configuration.
  - name: Loans
    x-surface: lms
    description: Loan applications, lifecycle commands, embedded schedules, and the servicing summary read model with payoff
      and APR.
  - name: Payments
    x-surface: lms
    description: Loan payment intents from creation through rail submission, posting, and provider-driven returns.
  - name: Autopay
    x-surface: lms
    description: Single current enrollment per loan, Regulation E authorization, and per-rail failure policies.
  - name: Funding
    x-surface: lms
    description: Approval-gated disbursements and outbound refunds to verified recipients.
  - name: Statements
    x-surface: lms
    description: Job-generated due-date statements with governed regeneration and PDF download.
  - name: Accounting
    x-surface: lms
    description: Balanced journal entries and the chart of accounts.
  - name: Charges
    x-surface: lms
    description: Charge definitions with immutable Regulation Z classification, and governed loan-charge commands.
  - name: Servicing actions
    x-surface: lms
    description: Governed loan commands under case governance and maker-checker, reschedules, interest pauses, and the
      governance ledger.
  - name: Restrictions
    x-surface: lms
    description: Customer- and loan-scoped holds enforced at execution time.
  - name: Reconciliation
    x-surface: lms
    description: Exceptions between provider events, money intents, and the ledger, with CSV export.
  - name: Merchant advances
    x-surface: lms
    description: Receivables purchases, sales reports, remittances, projections, and breach monitoring.
  - name: Reporting
    x-surface: lms
    description: The operational report-definition catalog.
security:
  - oauth2: []
paths:
  /v1/servicing/cases:
    post:
      tags:
        - Cases
      operationId: createCase
      summary: Create a case
      description: Creates or deduplicates a durable servicing matter and resolves its workflow version, queue, service
        levels, and first tasks.
      x-permission: CREATE_CASE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - caseType
                  - status
                  - stage
                  - priority
                  - customerId
                  - loanIds
                  - queueId
                  - nextAction
                  - version
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  caseType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  stage:
                    type: string
                  priority:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  loanIds:
                    type: array
                    items:
                      type: string
                  queueId:
                    type: string
                  nextAction:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                caseId: case_HBR_COL_51
                caseType: collections
                status: open
                stage: contact_strategy
                priority: high
                customerId: cus_72P0MAYA
                loanIds:
                  - loan_harbor_7X2K
                queueId: queue_early_collections
                nextAction: evaluate_contact_eligibility
                version: 6
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseType
                - customerId
                - loanIds
                - source
                - sourceReference
                - reasonCode
                - priority
              properties:
                caseType:
                  type: string
                customerId:
                  type: string
                  description: Stable opaque customer identifier.
                loanIds:
                  type: array
                  items:
                    type: string
                source:
                  type: string
                  description: System or actor that originated the record.
                sourceReference:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                priority:
                  type: string
              example:
                caseType: collections
                customerId: cus_72P0MAYA
                loanIds:
                  - loan_harbor_7X2K
                source: delinquency_monitor
                sourceReference: signal_2027-05-01_HBR
                reasonCode: installment_past_due
                priority: high
            example:
              caseType: collections
              customerId: cus_72P0MAYA
              loanIds:
                - loan_harbor_7X2K
              source: delinquency_monitor
              sourceReference: signal_2027-05-01_HBR
              reasonCode: installment_past_due
              priority: high
    get:
      tags:
        - Cases
      operationId: listCases
      summary: List cases
      description: Returns permission-filtered cases with cursor pagination and stable sort.
      x-permission: READ_CASE
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
          description: Filter by case status.
        - name: caseType
          in: query
          schema:
            type: string
          description: Filter by configured case type.
        - name: customerId
          in: query
          schema:
            type: string
          description: Stable opaque customer identifier.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - caseId
                        - caseType
                        - status
                        - stage
                        - priority
                        - customerId
                        - loanIds
                        - queueId
                        - nextAction
                        - version
                      properties:
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        caseType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        stage:
                          type: string
                        priority:
                          type: string
                        customerId:
                          type: string
                          description: Stable opaque customer identifier.
                        loanIds:
                          type: array
                          items:
                            type: string
                        queueId:
                          type: string
                        nextAction:
                          type: string
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - caseId: case_HBR_COL_51
                    caseType: collections
                    status: open
                    stage: contact_strategy
                    priority: high
                    customerId: cus_72P0MAYA
                    loanIds:
                      - loan_harbor_7X2K
                    queueId: queue_early_collections
                    nextAction: evaluate_contact_eligibility
                    version: 6
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/cases/{caseId}:
    get:
      tags:
        - Cases
      operationId: getCase
      summary: Retrieve a case
      description: Returns current case state, workflow stage, context freshness, deadlines, links, and next allowed transitions.
      x-permission: READ_CASE
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - caseType
                  - status
                  - stage
                  - priority
                  - customerId
                  - loanIds
                  - queueId
                  - nextAction
                  - version
                  - contextFreshness
                  - openTaskCount
                  - interactionCount
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  caseType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  stage:
                    type: string
                  priority:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  loanIds:
                    type: array
                    items:
                      type: string
                  queueId:
                    type: string
                  nextAction:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  contextFreshness:
                    type: string
                  openTaskCount:
                    type: integer
                  interactionCount:
                    type: integer
              example:
                caseId: case_HBR_COL_51
                caseType: collections
                status: open
                stage: contact_strategy
                priority: high
                customerId: cus_72P0MAYA
                loanIds:
                  - loan_harbor_7X2K
                queueId: queue_early_collections
                nextAction: evaluate_contact_eligibility
                version: 6
                contextFreshness: fresh
                openTaskCount: 2
                interactionCount: 4
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
    patch:
      tags:
        - Cases
      operationId: updateCase
      summary: Update case routing fields
      description: Updates mutable routing fields under optimistic concurrency; workflow state changes use the transition endpoint.
      x-permission: UPDATE_CASE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - caseType
                  - status
                  - stage
                  - priority
                  - customerId
                  - loanIds
                  - queueId
                  - nextAction
                  - version
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  caseType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  stage:
                    type: string
                  priority:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  loanIds:
                    type: array
                    items:
                      type: string
                  queueId:
                    type: string
                  nextAction:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                caseId: case_HBR_COL_51
                caseType: collections
                status: open
                stage: contact_strategy
                priority: urgent
                customerId: cus_72P0MAYA
                loanIds:
                  - loan_harbor_7X2K
                queueId: queue_supervisor_collections
                nextAction: evaluate_contact_eligibility
                version: 7
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - priority
                - queueId
                - expectedVersion
              properties:
                priority:
                  type: string
                queueId:
                  type: string
                expectedVersion:
                  type: integer
              example:
                priority: urgent
                queueId: queue_supervisor_collections
                expectedVersion: 6
            example:
              priority: urgent
              queueId: queue_supervisor_collections
              expectedVersion: 6
  /v1/servicing/cases/{caseId}/transitions:
    post:
      tags:
        - Cases
      operationId: transitionCase
      summary: Transition a case
      description: Applies one workflow-permitted transition after checking stage exit criteria.
      x-permission: TRANSITION_CASE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - previousStatus
                  - status
                  - stage
                  - version
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  previousStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  stage:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                caseId: case_HBR_COL_51
                previousStatus: open
                status: waiting_on_borrower
                stage: document_collection
                version: 7
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - transition
                - reasonCode
                - wakeAt
                - expectedVersion
              properties:
                transition:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                wakeAt:
                  type: string
                  format: date-time
                expectedVersion:
                  type: integer
              example:
                transition: wait_for_borrower
                reasonCode: documents_requested
                wakeAt: 2027-05-05T09:00:00-07:00
                expectedVersion: 6
            example:
              transition: wait_for_borrower
              reasonCode: documents_requested
              wakeAt: 2027-05-05T09:00:00-07:00
              expectedVersion: 6
  /v1/servicing/cases/{caseId}/close:
    post:
      tags:
        - Cases
      operationId: closeCase
      summary: Close a case
      description: Finalizes an already-resolved case with a structured outcome and closure reason.
      x-permission: CLOSE_CASE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - status
                  - outcome
                  - closedAt
                  - version
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  outcome:
                    type: string
                  closedAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                caseId: case_HBR_COL_51
                status: closed
                outcome: promise_kept
                closedAt: 2027-05-23T08:04:00-07:00
                version: 12
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
                - closureReason
                - expectedVersion
              properties:
                outcome:
                  type: string
                closureReason:
                  type: string
                expectedVersion:
                  type: integer
              example:
                outcome: promise_kept
                closureReason: authoritative_payment_confirmed
                expectedVersion: 11
            example:
              outcome: promise_kept
              closureReason: authoritative_payment_confirmed
              expectedVersion: 11
  /v1/servicing/cases/{caseId}/escalate:
    post:
      tags:
        - Cases
      operationId: escalateCase
      summary: Escalate a case
      description: Moves a case to its configured escalation route with urgency, reason, and service-level impact.
      x-permission: ESCALATE_CASE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - caseId
                  - status
                  - queueId
                  - escalationLevel
                properties:
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  queueId:
                    type: string
                  escalationLevel:
                    type: integer
              example:
                caseId: case_HBR_COL_51
                status: escalated
                queueId: queue_vulnerable_customer
                escalationLevel: 1
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - destination
                - note
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                destination:
                  type: string
                note:
                  type: string
              example:
                reasonCode: vulnerable_customer
                destination: supervisor_review
                note: Borrower requested specialist support.
            example:
              reasonCode: vulnerable_customer
              destination: supervisor_review
              note: Borrower requested specialist support.
  /v1/servicing/cases/{caseId}/timeline:
    get:
      tags:
        - Cases
      operationId: listCaseTimeline
      summary: List case timeline
      description: Returns a cursor-paginated, permission-aware timeline of state, task, interaction, decision, action, and
        evidence events.
      x-permission: READ_CASE
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - eventId
                        - type
                        - occurredAt
                        - actor
                        - summary
                      properties:
                        eventId:
                          type: string
                        type:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        actor:
                          type: string
                        summary:
                          type: string
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - eventId: evt_CASE_81
                    type: case.created
                    occurredAt: 2027-05-01T08:00:03-07:00
                    actor: delinquency_monitor
                    summary: Collections case opened at 22 days past due.
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/cases/{caseId}/evidence-export:
    post:
      tags:
        - Cases
      operationId: exportCaseEvidence
      summary: Export case evidence
      description: Creates a tamper-evident, access-filtered evidence package for the case.
      x-permission: EXPORT_CASE_EVIDENCE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "202":
          description: Accepted for asynchronous processing.
          content:
            application/json:
              schema:
                type: object
                required:
                  - exportId
                  - status
                  - caseId
                properties:
                  exportId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
              example:
                exportId: export_CASE_18
                status: processing
                caseId: case_HBR_COL_51
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - format
                - includeInteractions
                - includeRestrictedEvidence
              properties:
                format:
                  type: string
                  format: date-time
                includeInteractions:
                  type: boolean
                includeRestrictedEvidence:
                  type: boolean
              example:
                format: zip_json_pdf
                includeInteractions: true
                includeRestrictedEvidence: false
            example:
              format: zip_json_pdf
              includeInteractions: true
              includeRestrictedEvidence: false
  /v1/servicing/tasks:
    get:
      tags:
        - Tasks
      operationId: listTasks
      summary: List tasks
      description: Lists tasks visible to the caller by queue, state, case, skill, and due time.
      x-permission: READ_TASK
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: queueId
          in: query
          schema:
            type: string
          description: Filter by queue.
        - name: status
          in: query
          schema:
            type: string
          description: Filter by task status.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - taskId
                        - caseId
                        - type
                        - status
                        - priority
                        - queueId
                        - dueAt
                      properties:
                        taskId:
                          type: string
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        type:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        priority:
                          type: integer
                        queueId:
                          type: string
                        dueAt:
                          type: string
                          format: date-time
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - taskId: task_HBR_CALL_8
                    caseId: case_HBR_COL_51
                    type: outbound_contact
                    status: available
                    priority: 82
                    queueId: queue_early_collections
                    dueAt: 2027-05-01T17:00:00-07:00
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/queues/{queueId}/tasks/reserve-next:
    post:
      tags:
        - Tasks
      operationId: reserveNextTask
      summary: Reserve the next task
      description: Atomically selects and temporarily reserves the highest-ranked eligible task for the worker.
      x-permission: RESERVE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: queueId
          in: path
          required: true
          description: Stable opaque queue identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - caseId
                  - type
                  - status
                  - priority
                  - queueId
                  - dueAt
                  - reservedBy
                  - reservationExpiresAt
                properties:
                  taskId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  type:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  priority:
                    type: integer
                  queueId:
                    type: string
                  dueAt:
                    type: string
                    format: date-time
                  reservedBy:
                    type: string
                  reservationExpiresAt:
                    type: string
                    format: date-time
              example:
                taskId: task_HBR_CALL_8
                caseId: case_HBR_COL_51
                type: outbound_contact
                status: reserved
                priority: 82
                queueId: queue_early_collections
                dueAt: 2027-05-01T17:00:00-07:00
                reservedBy: worker_ANA_4
                reservationExpiresAt: 2027-05-01T10:02:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - workerId
                - skills
                - reservationSeconds
              properties:
                workerId:
                  type: string
                skills:
                  type: array
                  items:
                    type: string
                reservationSeconds:
                  type: integer
              example:
                workerId: worker_ANA_4
                skills:
                  - collections
                  - english
                reservationSeconds: 120
            example:
              workerId: worker_ANA_4
              skills:
                - collections
                - english
              reservationSeconds: 120
  /v1/servicing/tasks/{taskId}/accept:
    post:
      tags:
        - Tasks
      operationId: acceptTask
      summary: Accept a task
      description: Accept a task through the task state machine and records the actor, reason, and timestamp.
      x-permission: UPDATE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - version
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                taskId: task_HBR_CALL_8
                status: accepted
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - workerId
              properties:
                workerId:
                  type: string
              example:
                workerId: worker_ANA_4
            example:
              workerId: worker_ANA_4
  /v1/servicing/tasks/{taskId}/start:
    post:
      tags:
        - Tasks
      operationId: startTask
      summary: Start a task
      description: Start a task through the task state machine and records the actor, reason, and timestamp.
      x-permission: UPDATE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - version
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                taskId: task_HBR_CALL_8
                status: in_progress
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - workerId
              properties:
                workerId:
                  type: string
              example:
                workerId: worker_ANA_4
            example:
              workerId: worker_ANA_4
  /v1/servicing/tasks/{taskId}/complete:
    post:
      tags:
        - Tasks
      operationId: completeTask
      summary: Complete a task
      description: Complete a task through the task state machine and records the actor, reason, and timestamp.
      x-permission: UPDATE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - version
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                taskId: task_HBR_CALL_8
                status: completed
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
                - note
              properties:
                outcome:
                  type: string
                note:
                  type: string
              example:
                outcome: borrower_reached
                note: Promise terms captured.
            example:
              outcome: borrower_reached
              note: Promise terms captured.
  /v1/servicing/tasks/{taskId}/release:
    post:
      tags:
        - Tasks
      operationId: releaseTask
      summary: Release a task
      description: Release a task through the task state machine and records the actor, reason, and timestamp.
      x-permission: UPDATE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - version
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                taskId: task_HBR_CALL_8
                status: available
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: reservation_released
            example:
              reasonCode: reservation_released
  /v1/servicing/tasks/{taskId}/cancel:
    post:
      tags:
        - Tasks
      operationId: cancelTask
      summary: Cancel a task
      description: Cancel a task through the task state machine and records the actor, reason, and timestamp.
      x-permission: UPDATE_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - version
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                taskId: task_HBR_CALL_8
                status: cancelled
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: case_resolved
            example:
              reasonCode: case_resolved
  /v1/servicing/tasks/{taskId}/reassign:
    post:
      tags:
        - Tasks
      operationId: reassignTask
      summary: Reassign a task
      description: Reassigns a task to an eligible queue or worker with a recorded reason.
      x-permission: REASSIGN_TASK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: taskId
          in: path
          required: true
          description: Stable opaque task identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - taskId
                  - status
                  - queueId
                  - assignedWorkerId
                properties:
                  taskId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  queueId:
                    type: string
                  assignedWorkerId:
                    type: string
              example:
                taskId: task_HBR_CALL_8
                status: available
                queueId: queue_vulnerable_customer
                assignedWorkerId: null
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - queueId
                - workerId
                - reasonCode
              properties:
                queueId:
                  type: string
                workerId:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                queueId: queue_vulnerable_customer
                workerId: null
                reasonCode: specialist_skill_required
            example:
              queueId: queue_vulnerable_customer
              workerId: null
              reasonCode: specialist_skill_required
  /v1/servicing/interactions:
    post:
      tags:
        - Interactions
      operationId: createInteraction
      summary: Create an interaction
      description: Creates, schedules, or executes an inbound/outbound interaction and rechecks channel eligibility at execution.
      x-permission: CREATE_INTERACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - caseId
                  - direction
                  - channel
                  - purpose
                  - status
                  - outcome
                  - startedAt
                properties:
                  interactionId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  direction:
                    type: string
                  channel:
                    type: string
                  purpose:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  outcome:
                    type: string
                  startedAt:
                    type: string
                    format: date-time
              example:
                interactionId: int_HBR_CALL_91
                caseId: case_HBR_COL_51
                direction: outbound
                channel: voice
                purpose: collections
                status: completed
                outcome: verified_party_reached
                startedAt: 2027-05-01T10:12:03-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - direction
                - channel
                - purpose
                - contactPointId
                - content
              properties:
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                direction:
                  type: string
                channel:
                  type: string
                purpose:
                  type: string
                contactPointId:
                  type: string
                content:
                  type: object
                  required:
                    - scriptVersion
                  properties:
                    scriptVersion:
                      type: string
              example:
                caseId: case_HBR_COL_51
                direction: outbound
                channel: voice
                purpose: collections
                contactPointId: cp_MAYA_MOBILE_1
                content:
                  scriptVersion: collections-opening-v5
            example:
              caseId: case_HBR_COL_51
              direction: outbound
              channel: voice
              purpose: collections
              contactPointId: cp_MAYA_MOBILE_1
              content:
                scriptVersion: collections-opening-v5
    get:
      tags:
        - Interactions
      operationId: listInteractions
      summary: List interactions
      description: Lists permission-filtered interactions by case, customer, channel, direction, and time.
      x-permission: READ_INTERACTION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: caseId
          in: query
          schema:
            type: string
          description: Stable opaque servicing case identifier.
        - name: channel
          in: query
          schema:
            type: string
          description: Filter by communication channel.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - interactionId
                        - caseId
                        - direction
                        - channel
                        - purpose
                        - status
                        - outcome
                        - startedAt
                      properties:
                        interactionId:
                          type: string
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        direction:
                          type: string
                        channel:
                          type: string
                        purpose:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        outcome:
                          type: string
                        startedAt:
                          type: string
                          format: date-time
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - interactionId: int_HBR_CALL_91
                    caseId: case_HBR_COL_51
                    direction: outbound
                    channel: voice
                    purpose: collections
                    status: completed
                    outcome: verified_party_reached
                    startedAt: 2027-05-01T10:12:03-07:00
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/interactions/{interactionId}:
    get:
      tags:
        - Interactions
      operationId: getInteraction
      summary: Retrieve an interaction
      description: Returns normalized delivery, outcome, compliance, content, provider, and evidence links.
      x-permission: READ_INTERACTION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: interactionId
          in: path
          required: true
          description: Stable opaque interaction identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - caseId
                  - direction
                  - channel
                  - purpose
                  - status
                  - outcome
                  - startedAt
                  - complianceDecisionId
                  - contentHash
                  - evidenceIds
                properties:
                  interactionId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  direction:
                    type: string
                  channel:
                    type: string
                  purpose:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  outcome:
                    type: string
                  startedAt:
                    type: string
                    format: date-time
                  complianceDecisionId:
                    type: string
                  contentHash:
                    type: string
                  evidenceIds:
                    type: array
                    description: Evidence records supporting the request.
                    items:
                      type: string
              example:
                interactionId: int_HBR_CALL_91
                caseId: case_HBR_COL_51
                direction: outbound
                channel: voice
                purpose: collections
                status: completed
                outcome: verified_party_reached
                startedAt: 2027-05-01T10:12:03-07:00
                complianceDecisionId: dec_CONTACT_81
                contentHash: sha256:71ac…908e
                evidenceIds:
                  - evd_CALL_18
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/interactions/{interactionId}/cancel:
    post:
      tags:
        - Interactions
      operationId: cancelInteraction
      summary: Cancel a scheduled interaction
      description: Cancels an interaction before provider execution and preserves its schedule and reason.
      x-permission: CANCEL_INTERACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: interactionId
          in: path
          required: true
          description: Stable opaque interaction identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - status
                  - cancelledAt
                properties:
                  interactionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  cancelledAt:
                    type: string
                    format: date-time
              example:
                interactionId: int_SCHEDULED_11
                status: cancelled
                cancelledAt: 2027-05-01T09:14:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: case_resolved
            example:
              reasonCode: case_resolved
  /v1/servicing/interactions/{interactionId}/replies:
    post:
      tags:
        - Interactions
      operationId: replyToInteraction
      summary: Reply in an interaction thread
      description: Creates an outbound reply linked to the original thread with a fresh compliance decision.
      x-permission: CREATE_INTERACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: interactionId
          in: path
          required: true
          description: Stable opaque interaction identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - interactionId
                  - threadId
                  - status
                properties:
                  interactionId:
                    type: string
                  threadId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
              example:
                interactionId: int_HBR_EMAIL_92
                threadId: thread_HBR_8
                status: scheduled
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - channel
                - purpose
                - content
              properties:
                channel:
                  type: string
                purpose:
                  type: string
                content:
                  type: object
                  required:
                    - templateId
                    - variables
                  properties:
                    templateId:
                      type: string
                    variables:
                      type: object
                      required:
                        - secureUploadExpiresOn
                      properties:
                        secureUploadExpiresOn:
                          type: string
              example:
                channel: email
                purpose: document_follow_up
                content:
                  templateId: tpl_DOC_FOLLOWUP
                  variables:
                    secureUploadExpiresOn: 2027-05-08
            example:
              channel: email
              purpose: document_follow_up
              content:
                templateId: tpl_DOC_FOLLOWUP
                variables:
                  secureUploadExpiresOn: 2027-05-08
  /v1/servicing/compliance/evaluations:
    post:
      tags:
        - Compliance decisions
      operationId: evaluateCompliance
      summary: Evaluate an action
      description: Evaluates a proposed action against current facts and effective policies without executing it.
      x-permission: EVALUATE_COMPLIANCE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - decisionId
                  - outcome
                  - expiresAt
                  - rules
                  - factsFreshness
                properties:
                  decisionId:
                    type: string
                  outcome:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  rules:
                    type: array
                    items:
                      type: object
                      required:
                        - ruleId
                        - outcome
                      properties:
                        ruleId:
                          type: string
                        outcome:
                          type: string
                  factsFreshness:
                    type: string
              example:
                decisionId: dec_CONTACT_81
                outcome: allowed
                expiresAt: 2027-05-01T10:16:58-07:00
                rules:
                  - ruleId: contact-time-CA-v4
                    outcome: pass
                factsFreshness: fresh
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - action
                - subject
                - parameters
                - asOf
              properties:
                action:
                  type: string
                subject:
                  type: object
                  required:
                    - customerId
                    - loanIds
                  properties:
                    customerId:
                      type: string
                      description: Stable opaque customer identifier.
                    loanIds:
                      type: array
                      items:
                        type: string
                parameters:
                  type: object
                  description: Strict action-type-specific parameters.
                  required:
                    - channel
                    - purpose
                    - contactPointId
                  properties:
                    channel:
                      type: string
                    purpose:
                      type: string
                    contactPointId:
                      type: string
                asOf:
                  type: string
                  format: date-time
                  description: Time at which the source says the fact was true.
              example:
                action: send_interaction
                subject:
                  customerId: cus_72P0MAYA
                  loanIds:
                    - loan_harbor_7X2K
                parameters:
                  channel: voice
                  purpose: collections
                  contactPointId: cp_MAYA_MOBILE_1
                asOf: 2027-05-01T10:11:58-07:00
            example:
              action: send_interaction
              subject:
                customerId: cus_72P0MAYA
                loanIds:
                  - loan_harbor_7X2K
              parameters:
                channel: voice
                purpose: collections
                contactPointId: cp_MAYA_MOBILE_1
              asOf: 2027-05-01T10:11:58-07:00
  /v1/servicing/compliance/contact-eligibility:
    post:
      tags:
        - Compliance decisions
      operationId: evaluateContactEligibility
      summary: Evaluate contact eligibility
      description: Returns channel-specific contact eligibility, restrictions, convenient time, and remaining configured
        contact budget.
      x-permission: EVALUATE_COMPLIANCE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - decisionId
                  - outcome
                  - localTime
                  - contactBudget
                  - blockingRestrictions
                properties:
                  decisionId:
                    type: string
                  outcome:
                    type: string
                  localTime:
                    type: string
                  contactBudget:
                    type: object
                    required:
                      - attemptsRemaining
                      - windowEndsAt
                    properties:
                      attemptsRemaining:
                        type: integer
                      windowEndsAt:
                        type: string
                        format: date-time
                  blockingRestrictions:
                    type: array
                    items:
                      type: object
              example:
                decisionId: dec_CONTACT_81
                outcome: allowed
                localTime: 2027-05-01T10:11:58-07:00
                contactBudget:
                  attemptsRemaining: 3
                  windowEndsAt: 2027-05-05T23:59:59-07:00
                blockingRestrictions: []
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - customerId
                - loanId
                - channel
                - purpose
                - contactPointId
                - requestedAt
              properties:
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                customerId:
                  type: string
                  description: Stable opaque customer identifier.
                loanId:
                  type: string
                  description: Stable opaque loan identifier.
                channel:
                  type: string
                purpose:
                  type: string
                contactPointId:
                  type: string
                requestedAt:
                  type: string
                  format: date-time
              example:
                caseId: case_HBR_COL_51
                customerId: cus_72P0MAYA
                loanId: loan_harbor_7X2K
                channel: voice
                purpose: collections
                contactPointId: cp_MAYA_MOBILE_1
                requestedAt: 2027-05-01T10:11:58-07:00
            example:
              caseId: case_HBR_COL_51
              customerId: cus_72P0MAYA
              loanId: loan_harbor_7X2K
              channel: voice
              purpose: collections
              contactPointId: cp_MAYA_MOBILE_1
              requestedAt: 2027-05-01T10:11:58-07:00
  /v1/servicing/compliance/decisions/{decisionId}:
    get:
      tags:
        - Compliance decisions
      operationId: getComplianceDecision
      summary: Explain a compliance decision
      description: Returns the immutable rule trace, facts, provenance, policy versions, warnings, and expiry for one decision.
      x-permission: READ_COMPLIANCE_DECISION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: decisionId
          in: path
          required: true
          description: Stable opaque decision identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - decisionId
                  - outcome
                  - action
                  - facts
                  - rules
                properties:
                  decisionId:
                    type: string
                  outcome:
                    type: string
                  action:
                    type: string
                  facts:
                    type: array
                    items:
                      type: object
                      required:
                        - name
                        - value
                        - source
                        - asOf
                        - freshness
                      properties:
                        name:
                          type: string
                        value:
                          type: integer
                        source:
                          type: string
                          description: System or actor that originated the record.
                        asOf:
                          type: string
                          format: date-time
                          description: Time at which the source says the fact was true.
                        freshness:
                          type: string
                  rules:
                    type: array
                    items:
                      type: object
                      required:
                        - ruleId
                        - jurisdiction
                        - outcome
                        - effectiveVersion
                      properties:
                        ruleId:
                          type: string
                        jurisdiction:
                          type: string
                        outcome:
                          type: string
                        effectiveVersion:
                          type: string
              example:
                decisionId: dec_CONTACT_81
                outcome: allowed
                action: send_interaction
                facts:
                  - name: loan.daysPastDue
                    value: 22
                    source: lendeasy_core
                    asOf: 2027-05-01T10:11:56-07:00
                    freshness: fresh
                rules:
                  - ruleId: contact-time-CA-v4
                    jurisdiction: US-CA
                    outcome: pass
                    effectiveVersion: 2027-01-01
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/cases/{caseId}/promises:
    post:
      tags:
        - Promises
      operationId: createPromise
      summary: Create a promise-to-pay
      description: Creates a structured payment commitment and returns its guardrail and approval outcome.
      x-permission: CREATE_PROMISE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - promiseId
                  - caseId
                  - loanId
                  - status
                  - commitments
                  - guardrailDecision
                  - version
                properties:
                  promiseId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  loanId:
                    type: string
                    description: Stable opaque loan identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  commitments:
                    type: array
                    items:
                      type: object
                      required:
                        - amount
                        - dueDate
                      properties:
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        dueDate:
                          type: string
                          format: date
                  guardrailDecision:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                promiseId: ptp_HBR_71
                caseId: case_HBR_COL_51
                loanId: loan_harbor_7X2K
                status: active
                commitments:
                  - amount: "260.00"
                    dueDate: 2027-05-08
                  - amount: "257.14"
                    dueDate: 2027-05-22
                guardrailDecision: within_policy
                version: 1
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanId
                - commitments
                - sourceInteractionId
                - borrowerConfirmedAt
              properties:
                loanId:
                  type: string
                  description: Stable opaque loan identifier.
                commitments:
                  type: array
                  items:
                    type: object
                    required:
                      - amount
                      - dueDate
                    properties:
                      amount:
                        type: string
                        description: Decimal monetary amount encoded as a string.
                      dueDate:
                        type: string
                        format: date
                sourceInteractionId:
                  type: string
                borrowerConfirmedAt:
                  type: string
                  format: date-time
              example:
                loanId: loan_harbor_7X2K
                commitments:
                  - amount: "260.00"
                    dueDate: 2027-05-08
                  - amount: "257.14"
                    dueDate: 2027-05-22
                sourceInteractionId: int_HBR_CALL_91
                borrowerConfirmedAt: 2027-05-01T10:18:42-07:00
            example:
              loanId: loan_harbor_7X2K
              commitments:
                - amount: "260.00"
                  dueDate: 2027-05-08
                - amount: "257.14"
                  dueDate: 2027-05-22
              sourceInteractionId: int_HBR_CALL_91
              borrowerConfirmedAt: 2027-05-01T10:18:42-07:00
    get:
      tags:
        - Promises
      operationId: listPromises
      summary: List case promises
      description: Lists current and historical promises linked to a case.
      x-permission: READ_PROMISE
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - promiseId
                        - caseId
                        - loanId
                        - status
                        - commitments
                        - guardrailDecision
                        - version
                      properties:
                        promiseId:
                          type: string
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        loanId:
                          type: string
                          description: Stable opaque loan identifier.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        commitments:
                          type: array
                          items:
                            type: object
                            required:
                              - amount
                              - dueDate
                            properties:
                              amount:
                                type: string
                                description: Decimal monetary amount encoded as a string.
                              dueDate:
                                type: string
                                format: date
                        guardrailDecision:
                          type: string
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - promiseId: ptp_HBR_71
                    caseId: case_HBR_COL_51
                    loanId: loan_harbor_7X2K
                    status: active
                    commitments:
                      - amount: "260.00"
                        dueDate: 2027-05-08
                      - amount: "257.14"
                        dueDate: 2027-05-22
                    guardrailDecision: within_policy
                    version: 1
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/promises/{promiseId}:
    get:
      tags:
        - Promises
      operationId: getPromise
      summary: Retrieve a promise
      description: Returns terms, versions, guardrail trace, evaluation, covering payments, and outreach suppression.
      x-permission: READ_PROMISE
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: promiseId
          in: path
          required: true
          description: Stable opaque promise identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - promiseId
                  - caseId
                  - loanId
                  - status
                  - commitments
                  - guardrailDecision
                  - version
                  - evaluation
                  - suppression
                properties:
                  promiseId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  loanId:
                    type: string
                    description: Stable opaque loan identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  commitments:
                    type: array
                    items:
                      type: object
                      required:
                        - amount
                        - dueDate
                      properties:
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        dueDate:
                          type: string
                          format: date
                  guardrailDecision:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  evaluation:
                    type: object
                    required:
                      - nextAt
                      - paidAmount
                    properties:
                      nextAt:
                        type: string
                        format: date-time
                      paidAmount:
                        type: string
                  suppression:
                    type: object
                    required:
                      - collectionsOutreach
                      - through
                    properties:
                      collectionsOutreach:
                        type: boolean
                      through:
                        type: string
              example:
                promiseId: ptp_HBR_71
                caseId: case_HBR_COL_51
                loanId: loan_harbor_7X2K
                status: active
                commitments:
                  - amount: "260.00"
                    dueDate: 2027-05-08
                  - amount: "257.14"
                    dueDate: 2027-05-22
                guardrailDecision: within_policy
                version: 1
                evaluation:
                  nextAt: 2027-05-09T00:15:00-07:00
                  paidAmount: "0.00"
                suppression:
                  collectionsOutreach: true
                  through: 2027-05-22
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/promises/{promiseId}/revisions:
    post:
      tags:
        - Promises
      operationId: revisePromise
      summary: Revise a promise
      description: Creates a superseding promise version and reruns guardrails without rewriting the original commitment.
      x-permission: CREATE_PROMISE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: promiseId
          in: path
          required: true
          description: Stable opaque promise identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - promiseId
                  - caseId
                  - loanId
                  - status
                  - commitments
                  - guardrailDecision
                  - version
                  - supersedesPromiseId
                properties:
                  promiseId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  loanId:
                    type: string
                    description: Stable opaque loan identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  commitments:
                    type: array
                    items:
                      type: object
                      required:
                        - amount
                        - dueDate
                      properties:
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        dueDate:
                          type: string
                          format: date
                  guardrailDecision:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  supersedesPromiseId:
                    type: string
              example:
                promiseId: ptp_HBR_72
                caseId: case_HBR_COL_51
                loanId: loan_harbor_7X2K
                status: active
                commitments:
                  - amount: "517.14"
                    dueDate: 2027-05-22
                guardrailDecision: within_policy
                version: 1
                supersedesPromiseId: ptp_HBR_71
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - commitments
                - reasonCode
                - expectedVersion
              properties:
                commitments:
                  type: array
                  items:
                    type: object
                    required:
                      - amount
                      - dueDate
                    properties:
                      amount:
                        type: string
                        description: Decimal monetary amount encoded as a string.
                      dueDate:
                        type: string
                        format: date
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                expectedVersion:
                  type: integer
              example:
                commitments:
                  - amount: "517.14"
                    dueDate: 2027-05-22
                reasonCode: borrower_requested_single_payment
                expectedVersion: 1
            example:
              commitments:
                - amount: "517.14"
                  dueDate: 2027-05-22
              reasonCode: borrower_requested_single_payment
              expectedVersion: 1
  /v1/servicing/promises/{promiseId}/cancel:
    post:
      tags:
        - Promises
      operationId: cancelPromise
      summary: Cancel a promise
      description: Cancels an active promise with effective time and structured reason.
      x-permission: CANCEL_PROMISE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: promiseId
          in: path
          required: true
          description: Stable opaque promise identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - promiseId
                  - status
                  - version
                properties:
                  promiseId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                promiseId: ptp_HBR_71
                status: cancelled
                version: 2
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - effectiveAt
                - expectedVersion
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                effectiveAt:
                  type: string
                  format: date-time
                expectedVersion:
                  type: integer
              example:
                reasonCode: borrower_withdrew_commitment
                effectiveAt: 2027-05-03T11:20:00-07:00
                expectedVersion: 1
            example:
              reasonCode: borrower_withdrew_commitment
              effectiveAt: 2027-05-03T11:20:00-07:00
              expectedVersion: 1
  /v1/servicing/promises/{promiseId}/evaluate:
    post:
      tags:
        - Promises
      operationId: evaluatePromise
      summary: Re-evaluate a promise
      description: Re-reads authoritative payment facts and evaluates current promise state idempotently.
      x-permission: EVALUATE_PROMISE
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: promiseId
          in: path
          required: true
          description: Stable opaque promise identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - promiseId
                  - previousStatus
                  - status
                  - qualifyingPayments
                  - evaluatedAt
                properties:
                  promiseId:
                    type: string
                  previousStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  qualifyingPayments:
                    type: array
                    items:
                      type: string
                  evaluatedAt:
                    type: string
                    format: date-time
              example:
                promiseId: ptp_HBR_71
                previousStatus: active
                status: kept
                qualifyingPayments:
                  - pay_HBR_260
                  - pay_HBR_25714
                evaluatedAt: 2027-05-23T08:00:03-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - asOf
              properties:
                asOf:
                  type: string
                  format: date-time
                  description: Time at which the source says the fact was true.
              example:
                asOf: 2027-05-23T08:00:00-07:00
            example:
              asOf: 2027-05-23T08:00:00-07:00
  /v1/servicing/action-requests/preview:
    post:
      tags:
        - Action requests
      operationId: previewActionRequest
      summary: Preview an action request
      description: Evaluates capabilities, facts, financial/schedule effect, compliance, and approvals without preparing or
        executing an action.
      x-permission: PREPARE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - eligible
                  - previewToken
                  - expiresAt
                  - approvalRequired
                  - capability
                  - warnings
                properties:
                  eligible:
                    type: boolean
                  previewToken:
                    type: string
                    description: Short-lived token binding the preview to facts, policies, and payload.
                  expiresAt:
                    type: string
                    format: date-time
                  approvalRequired:
                    type: boolean
                  capability:
                    type: string
                  warnings:
                    type: array
                    items:
                      type: object
              example:
                eligible: true
                previewToken: prv_AR_71
                expiresAt: 2027-05-01T10:30:00-07:00
                approvalRequired: false
                capability: lms_provided
                warnings: []
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - loanId
                - actionType
                - parameters
              properties:
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                loanId:
                  type: string
                  description: Stable opaque loan identifier.
                actionType:
                  type: string
                parameters:
                  type: object
                  description: Strict action-type-specific parameters.
                  required:
                    - amount
                    - currency
                    - effectiveDate
                    - paymentInstrumentId
                  properties:
                    amount:
                      type: string
                      description: Decimal monetary amount encoded as a string.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                    effectiveDate:
                      type: string
                      format: date
                      description: Business-effective date in ISO 8601 format.
                    paymentInstrumentId:
                      type: string
              example:
                caseId: case_HBR_COL_51
                loanId: loan_harbor_7X2K
                actionType: take_payment
                parameters:
                  amount: "517.14"
                  currency: USD
                  effectiveDate: 2027-05-08
                  paymentInstrumentId: pi_HBR_ACH_04
            example:
              caseId: case_HBR_COL_51
              loanId: loan_harbor_7X2K
              actionType: take_payment
              parameters:
                amount: "517.14"
                currency: USD
                effectiveDate: 2027-05-08
                paymentInstrumentId: pi_HBR_ACH_04
  /v1/servicing/action-requests:
    post:
      tags:
        - Action requests
      operationId: createActionRequest
      summary: Prepare an action request
      description: Freezes a typed, case-linked action payload and its execution context.
      x-permission: PREPARE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - caseId
                  - actionType
                  - status
                  - approvalRequired
                  - requestedHash
                  - version
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  actionType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  approvalRequired:
                    type: boolean
                  requestedHash:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                actionRequestId: ar_HBR_811
                caseId: case_HBR_COL_51
                actionType: take_payment
                status: prepared
                approvalRequired: false
                requestedHash: sha256:49b1…72dd
                version: 1
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - loanId
                - actionType
                - parameters
                - previewToken
              properties:
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                loanId:
                  type: string
                  description: Stable opaque loan identifier.
                actionType:
                  type: string
                parameters:
                  type: object
                  description: Strict action-type-specific parameters.
                  required:
                    - amount
                    - currency
                    - effectiveDate
                    - paymentInstrumentId
                  properties:
                    amount:
                      type: string
                      description: Decimal monetary amount encoded as a string.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                    effectiveDate:
                      type: string
                      format: date
                      description: Business-effective date in ISO 8601 format.
                    paymentInstrumentId:
                      type: string
                previewToken:
                  type: string
                  description: Short-lived token binding the preview to facts, policies, and payload.
              example:
                caseId: case_HBR_COL_51
                loanId: loan_harbor_7X2K
                actionType: take_payment
                parameters:
                  amount: "517.14"
                  currency: USD
                  effectiveDate: 2027-05-08
                  paymentInstrumentId: pi_HBR_ACH_04
                previewToken: prv_AR_71
            example:
              caseId: case_HBR_COL_51
              loanId: loan_harbor_7X2K
              actionType: take_payment
              parameters:
                amount: "517.14"
                currency: USD
                effectiveDate: 2027-05-08
                paymentInstrumentId: pi_HBR_ACH_04
              previewToken: prv_AR_71
    get:
      tags:
        - Action requests
      operationId: listActionRequests
      summary: List action requests
      description: Lists action requests by case, loan, type, state, and execution mode.
      x-permission: READ_ACTION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: caseId
          in: query
          schema:
            type: string
          description: Stable opaque servicing case identifier.
        - name: status
          in: query
          schema:
            type: string
          description: Filter by action-request status.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - actionRequestId
                        - caseId
                        - actionType
                        - status
                        - approvalRequired
                        - requestedHash
                        - version
                      properties:
                        actionRequestId:
                          type: string
                          description: Stable opaque action-request identifier.
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        actionType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        approvalRequired:
                          type: boolean
                        requestedHash:
                          type: string
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - actionRequestId: ar_HBR_811
                    caseId: case_HBR_COL_51
                    actionType: take_payment
                    status: prepared
                    approvalRequired: false
                    requestedHash: sha256:49b1…72dd
                    version: 1
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/action-requests/{actionRequestId}:
    get:
      tags:
        - Action requests
      operationId: getActionRequest
      summary: Retrieve an action request
      description: Returns requested and applied payloads, approvals, attempts, acknowledgements, and reconciliation.
      x-permission: READ_ACTION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: actionRequestId
          in: path
          required: true
          description: Stable opaque action-request identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - caseId
                  - actionType
                  - status
                  - approvalRequired
                  - requestedHash
                  - version
                  - attempts
                  - approvals
                  - reconciliationStatus
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  actionType:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  approvalRequired:
                    type: boolean
                  requestedHash:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  attempts:
                    type: array
                    items:
                      type: object
                  approvals:
                    type: array
                    items:
                      type: object
                  reconciliationStatus:
                    type: string
              example:
                actionRequestId: ar_HBR_811
                caseId: case_HBR_COL_51
                actionType: take_payment
                status: prepared
                approvalRequired: false
                requestedHash: sha256:49b1…72dd
                version: 1
                attempts: []
                approvals: []
                reconciliationStatus: not_started
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/action-requests/{actionRequestId}/approve:
    post:
      tags:
        - Action requests
      operationId: approveActionRequest
      summary: Approve an action request
      description: Approve an action request against the frozen action hash and records a durable decision.
      x-permission: APPROVE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
            - actions:approve
      parameters:
        - name: actionRequestId
          in: path
          required: true
          description: Stable opaque action-request identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - status
                  - version
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                actionRequestId: ar_HBR_811
                status: approved
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - note
              properties:
                decision:
                  type: string
                note:
                  type: string
              example:
                decision: approve
                note: Terms and evidence reviewed.
            example:
              decision: approve
              note: Terms and evidence reviewed.
  /v1/servicing/action-requests/{actionRequestId}/reject:
    post:
      tags:
        - Action requests
      operationId: rejectActionRequest
      summary: Reject an action request
      description: Reject an action request against the frozen action hash and records a durable decision.
      x-permission: APPROVE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
            - actions:approve
      parameters:
        - name: actionRequestId
          in: path
          required: true
          description: Stable opaque action-request identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - status
                  - version
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                actionRequestId: ar_HBR_811
                status: rejected
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - reasonCode
              properties:
                decision:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                decision: reject
                reasonCode: insufficient_evidence
            example:
              decision: reject
              reasonCode: insufficient_evidence
  /v1/servicing/action-requests/{actionRequestId}/submit:
    post:
      tags:
        - Action requests
      operationId: submitActionRequest
      summary: Submit an action request
      description: Submit an action request against the frozen action hash and records a durable decision.
      x-permission: EXECUTE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: actionRequestId
          in: path
          required: true
          description: Stable opaque action-request identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - status
                  - version
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                actionRequestId: ar_HBR_811
                status: submitted
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - expectedVersion
              properties:
                expectedVersion:
                  type: integer
              example:
                expectedVersion: 2
            example:
              expectedVersion: 2
  /v1/servicing/action-requests/{actionRequestId}/cancel:
    post:
      tags:
        - Action requests
      operationId: cancelActionRequest
      summary: Cancel an action request
      description: Cancel an action request against the frozen action hash and records a durable decision.
      x-permission: PREPARE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: actionRequestId
          in: path
          required: true
          description: Stable opaque action-request identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionRequestId
                  - status
                  - version
                properties:
                  actionRequestId:
                    type: string
                    description: Stable opaque action-request identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                actionRequestId: ar_HBR_811
                status: cancelled
                version: 3
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: borrower_changed_request
            example:
              reasonCode: borrower_changed_request
  /v1/servicing/cases/{caseId}/documents:
    post:
      tags:
        - Case documents
      operationId: registerCaseDocument
      summary: Register a case document
      description: Registers metadata and returns a controlled upload target; bytes are scanned before availability.
      x-permission: CREATE_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - caseId
                  - type
                  - status
                  - fileName
                  - mediaType
                  - sha256
                  - version
                  - upload
                properties:
                  documentId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  type:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  fileName:
                    type: string
                  mediaType:
                    type: string
                  sha256:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  upload:
                    type: object
                    required:
                      - method
                      - expiresAt
                    properties:
                      method:
                        type: string
                      expiresAt:
                        type: string
                        format: date-time
              example:
                documentId: doc_CED_PAYSTUB_2
                caseId: case_CEDAR_HARDSHIP_4
                type: income_evidence
                status: registered
                fileName: pay-statement-april.pdf
                mediaType: application/pdf
                sha256: sha256:2d8c…188a
                version: 1
                upload:
                  method: PUT
                  expiresAt: 2027-05-01T11:00:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - fileName
                - mediaType
                - byteLength
                - sha256
              properties:
                type:
                  type: string
                fileName:
                  type: string
                mediaType:
                  type: string
                byteLength:
                  type: integer
                sha256:
                  type: string
              example:
                type: income_evidence
                fileName: pay-statement-april.pdf
                mediaType: application/pdf
                byteLength: 184220
                sha256: sha256:2d8c…188a
            example:
              type: income_evidence
              fileName: pay-statement-april.pdf
              mediaType: application/pdf
              byteLength: 184220
              sha256: sha256:2d8c…188a
    get:
      tags:
        - Case documents
      operationId: listCaseDocuments
      summary: List case documents
      description: Lists document metadata allowed for the caller without exposing storage paths.
      x-permission: READ_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: caseId
          in: path
          required: true
          description: Stable opaque servicing case identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - caseId
                        - type
                        - status
                        - fileName
                        - mediaType
                        - sha256
                        - version
                      properties:
                        documentId:
                          type: string
                        caseId:
                          type: string
                          description: Stable opaque servicing case identifier.
                        type:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        fileName:
                          type: string
                        mediaType:
                          type: string
                        sha256:
                          type: string
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - documentId: doc_CED_PAYSTUB_2
                    caseId: case_CEDAR_HARDSHIP_4
                    type: income_evidence
                    status: registered
                    fileName: pay-statement-april.pdf
                    mediaType: application/pdf
                    sha256: sha256:2d8c…188a
                    version: 1
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/documents/{documentId}:
    get:
      tags:
        - Case documents
      operationId: getCaseDocument
      summary: Retrieve document metadata
      description: Returns classification, scan, review, retention, and evidence metadata.
      x-permission: READ_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - caseId
                  - type
                  - status
                  - fileName
                  - mediaType
                  - sha256
                  - version
                  - scan
                  - retention
                properties:
                  documentId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  type:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  fileName:
                    type: string
                  mediaType:
                    type: string
                  sha256:
                    type: string
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  scan:
                    type: object
                    required:
                      - result
                    properties:
                      result:
                        type: string
                  retention:
                    type: object
                    required:
                      - hold
                      - policy
                    properties:
                      hold:
                        type: boolean
                      policy:
                        type: string
              example:
                documentId: doc_CED_PAYSTUB_2
                caseId: case_CEDAR_HARDSHIP_4
                type: income_evidence
                status: available
                fileName: pay-statement-april.pdf
                mediaType: application/pdf
                sha256: sha256:2d8c…188a
                version: 1
                scan:
                  result: clean
                retention:
                  hold: false
                  policy: servicing_evidence
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/documents/{documentId}/review:
    post:
      tags:
        - Case documents
      operationId: reviewCaseDocument
      summary: Review a document
      description: Records structured acceptance, rejection, classification correction, and reviewer evidence.
      x-permission: REVIEW_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - status
                  - decision
                  - reviewedAt
                properties:
                  documentId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  decision:
                    type: string
                  reviewedAt:
                    type: string
                    format: date-time
              example:
                documentId: doc_CED_PAYSTUB_2
                status: reviewed
                decision: accepted
                reviewedAt: 2027-05-01T11:08:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - classification
                - note
              properties:
                decision:
                  type: string
                classification:
                  type: string
                note:
                  type: string
              example:
                decision: accepted
                classification: income_evidence
                note: Name and pay period verified.
            example:
              decision: accepted
              classification: income_evidence
              note: Name and pay period verified.
  /v1/servicing/documents/{documentId}/download:
    get:
      tags:
        - Case documents
      operationId: downloadCaseDocument
      summary: Create a document download
      description: Returns a short-lived, tenant-scoped URL after access evaluation.
      x-permission: DOWNLOAD_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - downloadUrl
                  - expiresAt
                  - sha256
                properties:
                  documentId:
                    type: string
                  downloadUrl:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  sha256:
                    type: string
              example:
                documentId: doc_CED_PAYSTUB_2
                downloadUrl: https://download.lendeasy.ai/d/opaque-signed-value
                expiresAt: 2027-05-01T11:18:00-07:00
                sha256: sha256:2d8c…188a
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/verification-sessions:
    post:
      tags:
        - Verification
      operationId: createVerificationSession
      summary: Create a verification session
      description: Creates a purpose-bound verification session and returns allowed challenges without exposing answers.
      x-permission: CREATE_VERIFICATION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - verificationSessionId
                  - customerId
                  - purpose
                  - status
                  - expiresAt
                  - attemptsRemaining
                properties:
                  verificationSessionId:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  purpose:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  expiresAt:
                    type: string
                    format: date-time
                  attemptsRemaining:
                    type: integer
              example:
                verificationSessionId: ver_MAYA_81
                customerId: cus_72P0MAYA
                purpose: account_access
                status: challenge_required
                expiresAt: 2027-05-01T10:30:00-07:00
                attemptsRemaining: 2
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerId
                - caseId
                - purpose
                - channel
              properties:
                customerId:
                  type: string
                  description: Stable opaque customer identifier.
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                purpose:
                  type: string
                channel:
                  type: string
              example:
                customerId: cus_72P0MAYA
                caseId: case_HBR_COL_51
                purpose: account_access
                channel: voice
            example:
              customerId: cus_72P0MAYA
              caseId: case_HBR_COL_51
              purpose: account_access
              channel: voice
  /v1/servicing/verification-sessions/{verificationSessionId}:
    get:
      tags:
        - Verification
      operationId: getVerificationSession
      summary: Retrieve a verification session
      description: Returns state, expiry, attempts, satisfied factors, and permitted next steps.
      x-permission: READ_VERIFICATION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: verificationSessionId
          in: path
          required: true
          description: Stable opaque verificationSession identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - verificationSessionId
                  - customerId
                  - purpose
                  - status
                  - expiresAt
                  - attemptsRemaining
                properties:
                  verificationSessionId:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  purpose:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  expiresAt:
                    type: string
                    format: date-time
                  attemptsRemaining:
                    type: integer
              example:
                verificationSessionId: ver_MAYA_81
                customerId: cus_72P0MAYA
                purpose: account_access
                status: challenge_required
                expiresAt: 2027-05-01T10:30:00-07:00
                attemptsRemaining: 2
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/verification-sessions/{verificationSessionId}/answers:
    post:
      tags:
        - Verification
      operationId: submitVerificationAnswers
      summary: Submit verification answers
      description: Evaluates supplied challenge answers without returning stored expected values.
      x-permission: COMPLETE_VERIFICATION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: verificationSessionId
          in: path
          required: true
          description: Stable opaque verificationSession identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - verificationSessionId
                  - status
                  - assuranceLevel
                  - verifiedAt
                properties:
                  verificationSessionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  assuranceLevel:
                    type: string
                  verifiedAt:
                    type: string
                    format: date-time
              example:
                verificationSessionId: ver_MAYA_81
                status: verified
                assuranceLevel: standard
                verifiedAt: 2027-05-01T10:14:02-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - answers
              properties:
                answers:
                  type: array
                  items:
                    type: object
                    required:
                      - challengeId
                      - value
                    properties:
                      challengeId:
                        type: string
                      value:
                        type: string
              example:
                answers:
                  - challengeId: challenge_postal_code
                    value: "95814"
            example:
              answers:
                - challengeId: challenge_postal_code
                  value: "95814"
  /v1/servicing/verification-sessions/{verificationSessionId}/fail:
    post:
      tags:
        - Verification
      operationId: failVerificationSession
      summary: End an unsuccessful verification
      description: Ends the session with a normalized reason and triggers configured safeguards.
      x-permission: COMPLETE_VERIFICATION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: verificationSessionId
          in: path
          required: true
          description: Stable opaque verificationSession identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - verificationSessionId
                  - status
                  - attemptsRemaining
                properties:
                  verificationSessionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptsRemaining:
                    type: integer
              example:
                verificationSessionId: ver_MAYA_81
                status: failed
                attemptsRemaining: 0
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: attempts_exhausted
            example:
              reasonCode: attempts_exhausted
  /v1/servicing/ai-sessions:
    post:
      tags:
        - AI sessions
      operationId: createAiSession
      summary: Create an AI work session
      description: Starts a bounded session from a signed work packet with allowed facts, tools, budgets, and prohibited actions.
      x-permission: CREATE_AI_SESSION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - aiSessionId
                  - caseId
                  - agentProfile
                  - autonomyLevel
                  - status
                  - workPacketVersion
                  - expiresAt
                properties:
                  aiSessionId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  agentProfile:
                    type: string
                  autonomyLevel:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  workPacketVersion:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
              example:
                aiSessionId: ais_CASE_71
                caseId: case_HBR_COL_51
                agentProfile: collections_assistant
                autonomyLevel: A2
                status: active
                workPacketVersion: wp_2027-04-1
                expiresAt: 2027-05-01T10:45:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - caseId
                - agentProfile
                - objective
                - autonomyLevel
              properties:
                caseId:
                  type: string
                  description: Stable opaque servicing case identifier.
                agentProfile:
                  type: string
                objective:
                  type: string
                autonomyLevel:
                  type: string
              example:
                caseId: case_HBR_COL_51
                agentProfile: collections_assistant
                objective: Summarize the case and recommend the next compliant step.
                autonomyLevel: A2
            example:
              caseId: case_HBR_COL_51
              agentProfile: collections_assistant
              objective: Summarize the case and recommend the next compliant step.
              autonomyLevel: A2
  /v1/servicing/ai-sessions/{aiSessionId}:
    get:
      tags:
        - AI sessions
      operationId: getAiSession
      summary: Retrieve an AI session
      description: Returns work-packet version, tool ledger, budgets, outputs, review, and stop state.
      x-permission: READ_AI_SESSION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: aiSessionId
          in: path
          required: true
          description: Stable opaque aiSession identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - aiSessionId
                  - caseId
                  - agentProfile
                  - autonomyLevel
                  - status
                  - workPacketVersion
                  - expiresAt
                  - toolCalls
                  - outputCount
                  - budget
                properties:
                  aiSessionId:
                    type: string
                  caseId:
                    type: string
                    description: Stable opaque servicing case identifier.
                  agentProfile:
                    type: string
                  autonomyLevel:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  workPacketVersion:
                    type: string
                  expiresAt:
                    type: string
                    format: date-time
                  toolCalls:
                    type: integer
                  outputCount:
                    type: integer
                  budget:
                    type: object
                    required:
                      - toolCallsRemaining
                      - tokensRemaining
                    properties:
                      toolCallsRemaining:
                        type: integer
                      tokensRemaining:
                        type: integer
              example:
                aiSessionId: ais_CASE_71
                caseId: case_HBR_COL_51
                agentProfile: collections_assistant
                autonomyLevel: A2
                status: active
                workPacketVersion: wp_2027-04-1
                expiresAt: 2027-05-01T10:45:00-07:00
                toolCalls: 4
                outputCount: 1
                budget:
                  toolCallsRemaining: 6
                  tokensRemaining: 4200
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/ai-sessions/{aiSessionId}/outputs:
    post:
      tags:
        - AI sessions
      operationId: submitAiOutput
      summary: Submit an AI output
      description: Stores a proposed summary, recommendation, or draft with citations to allowed facts and evidence.
      x-permission: CREATE_AI_OUTPUT
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: aiSessionId
          in: path
          required: true
          description: Stable opaque aiSession identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outputId
                  - aiSessionId
                  - status
                  - reviewRequired
                properties:
                  outputId:
                    type: string
                  aiSessionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  reviewRequired:
                    type: boolean
              example:
                outputId: aio_81
                aiSessionId: ais_CASE_71
                status: produced
                reviewRequired: true
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - content
                - citations
                - confidence
              properties:
                type:
                  type: string
                content:
                  type: string
                citations:
                  type: array
                  items:
                    type: object
                    required:
                      - fact
                      - evidenceId
                    properties:
                      fact:
                        type: string
                      evidenceId:
                        type: string
                confidence:
                  type: string
              example:
                type: next_action_recommendation
                content: Offer the in-policy two-installment promise option.
                citations:
                  - fact: loan.amountPastDue
                    evidenceId: evd_FACT_81
                confidence: high
            example:
              type: next_action_recommendation
              content: Offer the in-policy two-installment promise option.
              citations:
                - fact: loan.amountPastDue
                  evidenceId: evd_FACT_81
              confidence: high
  /v1/servicing/ai-outputs/{outputId}/review:
    post:
      tags:
        - AI sessions
      operationId: reviewAiOutput
      summary: Review an AI output
      description: Accepts, edits, rejects, ignores, escalates, or blocks a proposed AI output with reason.
      x-permission: REVIEW_AI_OUTPUT
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: outputId
          in: path
          required: true
          description: Stable opaque output identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - outputId
                  - status
                  - reviewedBy
                  - reviewedAt
                properties:
                  outputId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  reviewedBy:
                    type: string
                  reviewedAt:
                    type: string
                    format: date-time
              example:
                outputId: aio_81
                status: accepted
                reviewedBy: worker_SUP_4
                reviewedAt: 2027-05-01T10:23:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - decision
                - reasonCode
              properties:
                decision:
                  type: string
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                decision: accepted
                reasonCode: facts_and_policy_verified
            example:
              decision: accepted
              reasonCode: facts_and_policy_verified
  /v1/servicing/ai-sessions/{aiSessionId}/stop:
    post:
      tags:
        - AI sessions
      operationId: stopAiSession
      summary: Stop an AI session
      description: Revokes tool access for the session and records the stop source and reason.
      x-permission: STOP_AI_SESSION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: aiSessionId
          in: path
          required: true
          description: Stable opaque aiSession identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - aiSessionId
                  - status
                  - stoppedAt
                properties:
                  aiSessionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  stoppedAt:
                    type: string
                    format: date-time
              example:
                aiSessionId: ais_CASE_71
                status: stopped
                stoppedAt: 2027-05-01T10:24:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: human_took_ownership
            example:
              reasonCode: human_took_ownership
  /v1/servicing/privacy-requests:
    post:
      tags:
        - Privacy requests
      operationId: createPrivacyRequest
      summary: Create a privacy request
      description: Creates an access, correction, deletion, or portability workflow with identity-verification and deadline policy.
      x-permission: CREATE_PRIVACY_REQUEST
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - privacyRequestId
                  - customerId
                  - type
                  - status
                  - jurisdiction
                  - dueAt
                  - version
                properties:
                  privacyRequestId:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  type:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  jurisdiction:
                    type: string
                  dueAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                privacyRequestId: prvreq_MAYA_4
                customerId: cus_72P0MAYA
                type: access
                status: intake
                jurisdiction: US-CA
                dueAt: 2027-06-15T23:59:59-07:00
                version: 1
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - customerId
                - type
                - jurisdiction
                - receivedAt
                - sourceInteractionId
              properties:
                customerId:
                  type: string
                  description: Stable opaque customer identifier.
                type:
                  type: string
                jurisdiction:
                  type: string
                receivedAt:
                  type: string
                  format: date-time
                sourceInteractionId:
                  type: string
              example:
                customerId: cus_72P0MAYA
                type: access
                jurisdiction: US-CA
                receivedAt: 2027-05-01T09:40:00-07:00
                sourceInteractionId: int_PRIVACY_4
            example:
              customerId: cus_72P0MAYA
              type: access
              jurisdiction: US-CA
              receivedAt: 2027-05-01T09:40:00-07:00
              sourceInteractionId: int_PRIVACY_4
    get:
      tags:
        - Privacy requests
      operationId: listPrivacyRequests
      summary: List privacy requests
      description: Lists requests by state, type, jurisdiction, customer, and deadline.
      x-permission: READ_PRIVACY_REQUEST
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - privacyRequestId
                        - customerId
                        - type
                        - status
                        - jurisdiction
                        - dueAt
                        - version
                      properties:
                        privacyRequestId:
                          type: string
                        customerId:
                          type: string
                          description: Stable opaque customer identifier.
                        type:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        jurisdiction:
                          type: string
                        dueAt:
                          type: string
                          format: date-time
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - privacyRequestId: prvreq_MAYA_4
                    customerId: cus_72P0MAYA
                    type: access
                    status: intake
                    jurisdiction: US-CA
                    dueAt: 2027-06-15T23:59:59-07:00
                    version: 1
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/privacy-requests/{privacyRequestId}:
    get:
      tags:
        - Privacy requests
      operationId: getPrivacyRequest
      summary: Retrieve a privacy request
      description: Returns verification, data-source tasks, holds, exceptions, exports, and deadline history.
      x-permission: READ_PRIVACY_REQUEST
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: privacyRequestId
          in: path
          required: true
          description: Stable opaque privacyRequest identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - privacyRequestId
                  - customerId
                  - type
                  - status
                  - jurisdiction
                  - dueAt
                  - version
                  - verificationStatus
                  - dataSources
                properties:
                  privacyRequestId:
                    type: string
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  type:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  jurisdiction:
                    type: string
                  dueAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  verificationStatus:
                    type: string
                  dataSources:
                    type: array
                    items:
                      type: object
                      required:
                        - name
                        - status
                      properties:
                        name:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
              example:
                privacyRequestId: prvreq_MAYA_4
                customerId: cus_72P0MAYA
                type: access
                status: intake
                jurisdiction: US-CA
                dueAt: 2027-06-15T23:59:59-07:00
                version: 1
                verificationStatus: pending
                dataSources:
                  - name: servicing
                    status: queued
                  - name: lending_core
                    status: queued
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/privacy-requests/{privacyRequestId}/complete:
    post:
      tags:
        - Privacy requests
      operationId: completePrivacyRequest
      summary: Complete a privacy request
      description: Finalizes the request only when required source tasks, exception reviews, and delivery evidence are complete.
      x-permission: COMPLETE_PRIVACY_REQUEST
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: privacyRequestId
          in: path
          required: true
          description: Stable opaque privacyRequest identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - privacyRequestId
                  - status
                  - outcome
                  - completedAt
                properties:
                  privacyRequestId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  outcome:
                    type: string
                  completedAt:
                    type: string
                    format: date-time
              example:
                privacyRequestId: prvreq_MAYA_4
                status: completed
                outcome: fulfilled
                completedAt: 2027-05-18T15:10:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - outcome
                - responseDocumentId
                - deliveryInteractionId
              properties:
                outcome:
                  type: string
                responseDocumentId:
                  type: string
                deliveryInteractionId:
                  type: string
              example:
                outcome: fulfilled
                responseDocumentId: doc_PRIVACY_RESPONSE_4
                deliveryInteractionId: int_PRIVACY_EMAIL_8
            example:
              outcome: fulfilled
              responseDocumentId: doc_PRIVACY_RESPONSE_4
              deliveryInteractionId: int_PRIVACY_EMAIL_8
  /v1/servicing/webhook-subscriptions:
    post:
      tags:
        - Webhooks
      operationId: createWebhookSubscription
      summary: Create a webhook subscription
      description: Creates a tenant-owned HTTPS subscription and returns the signing secret exactly once.
      x-permission: MANAGE_WEBHOOK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhookSubscriptionId
                  - status
                  - url
                  - eventTypes
                  - apiVersion
                  - secretVersion
                  - createdAt
                  - version
                  - signingSecret
                properties:
                  webhookSubscriptionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  url:
                    type: string
                  eventTypes:
                    type: array
                    items:
                      type: string
                  apiVersion:
                    type: string
                  secretVersion:
                    type: integer
                  createdAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  signingSecret:
                    type: string
              example:
                webhookSubscriptionId: whsub_PORTFOLIO_7
                status: pending_verification
                url: https://events.example.test/lendeasy
                eventTypes:
                  - payment.posted
                  - payment.returned
                  - funding.posted
                  - case.transitioned
                apiVersion: 2026-07-01
                secretVersion: 2
                createdAt: 2026-08-01T18:00:00Z
                version: 1
                signingSecret: whsec_sandbox_once_7K2P
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
                - eventTypes
                - apiVersion
                - description
              properties:
                url:
                  type: string
                eventTypes:
                  type: array
                  items:
                    type: string
                apiVersion:
                  type: string
                description:
                  type: string
              example:
                url: https://events.example.test/lendeasy
                eventTypes:
                  - payment.posted
                  - payment.returned
                  - funding.posted
                  - case.transitioned
                apiVersion: 2026-07-01
                description: Portfolio event consumer
            example:
              url: https://events.example.test/lendeasy
              eventTypes:
                - payment.posted
                - payment.returned
                - funding.posted
                - case.transitioned
              apiVersion: 2026-07-01
              description: Portfolio event consumer
    get:
      tags:
        - Webhooks
      operationId: listWebhookSubscriptions
      summary: List webhook subscriptions
      description: Lists destinations, event filters, state, secret version, and recent delivery health without returning secrets.
      x-permission: READ_WEBHOOK
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
          description: Filter by subscription state.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - webhookSubscriptionId
                        - status
                        - url
                        - eventTypes
                        - apiVersion
                        - secretVersion
                        - createdAt
                        - version
                      properties:
                        webhookSubscriptionId:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        url:
                          type: string
                        eventTypes:
                          type: array
                          items:
                            type: string
                        apiVersion:
                          type: string
                        secretVersion:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - webhookSubscriptionId: whsub_PORTFOLIO_7
                    status: active
                    url: https://events.example.test/lendeasy
                    eventTypes:
                      - payment.posted
                      - payment.returned
                      - funding.posted
                      - case.transitioned
                    apiVersion: 2026-07-01
                    secretVersion: 2
                    createdAt: 2026-08-01T18:00:00Z
                    version: 3
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/webhook-subscriptions/{webhookSubscriptionId}:
    get:
      tags:
        - Webhooks
      operationId: getWebhookSubscription
      summary: Retrieve a webhook subscription
      description: Returns configuration, health, version, and delivery summary; signing secrets are write-only.
      x-permission: READ_WEBHOOK
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhookSubscriptionId
                  - status
                  - url
                  - eventTypes
                  - apiVersion
                  - secretVersion
                  - createdAt
                  - version
                  - deliveryHealth
                properties:
                  webhookSubscriptionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  url:
                    type: string
                  eventTypes:
                    type: array
                    items:
                      type: string
                  apiVersion:
                    type: string
                  secretVersion:
                    type: integer
                  createdAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
                  deliveryHealth:
                    type: object
                    required:
                      - lastSucceededAt
                      - consecutiveFailures
                    properties:
                      lastSucceededAt:
                        type: string
                        format: date-time
                      consecutiveFailures:
                        type: integer
              example:
                webhookSubscriptionId: whsub_PORTFOLIO_7
                status: active
                url: https://events.example.test/lendeasy
                eventTypes:
                  - payment.posted
                  - payment.returned
                  - funding.posted
                  - case.transitioned
                apiVersion: 2026-07-01
                secretVersion: 2
                createdAt: 2026-08-01T18:00:00Z
                version: 3
                deliveryHealth:
                  lastSucceededAt: 2026-09-15T14:22:09Z
                  consecutiveFailures: 0
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
    patch:
      tags:
        - Webhooks
      operationId: updateWebhookSubscription
      summary: Update a webhook subscription
      description: Updates destination or event filters under optimistic concurrency and re-verifies a changed destination.
      x-permission: MANAGE_WEBHOOK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhookSubscriptionId
                  - status
                  - url
                  - eventTypes
                  - apiVersion
                  - secretVersion
                  - createdAt
                  - version
                properties:
                  webhookSubscriptionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  url:
                    type: string
                  eventTypes:
                    type: array
                    items:
                      type: string
                  apiVersion:
                    type: string
                  secretVersion:
                    type: integer
                  createdAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                webhookSubscriptionId: whsub_PORTFOLIO_7
                status: active
                url: https://events.example.test/lendeasy
                eventTypes:
                  - payment.posted
                  - payment.returned
                  - case.transitioned
                apiVersion: 2026-07-01
                secretVersion: 2
                createdAt: 2026-08-01T18:00:00Z
                version: 4
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - eventTypes
                - expectedVersion
              properties:
                eventTypes:
                  type: array
                  items:
                    type: string
                expectedVersion:
                  type: integer
              example:
                eventTypes:
                  - payment.posted
                  - payment.returned
                  - case.transitioned
                expectedVersion: 3
            example:
              eventTypes:
                - payment.posted
                - payment.returned
                - case.transitioned
              expectedVersion: 3
  /v1/servicing/webhook-subscriptions/{webhookSubscriptionId}/rotate-secret:
    post:
      tags:
        - Webhooks
      operationId: rotateWebhookSecret
      summary: Rotate a webhook signing secret
      description: Creates a new signing secret with a bounded overlap window and returns the new value once.
      x-permission: MANAGE_WEBHOOK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhookSubscriptionId
                  - signingSecret
                  - secretVersion
                  - previousSecretExpiresAt
                  - version
                properties:
                  webhookSubscriptionId:
                    type: string
                  signingSecret:
                    type: string
                  secretVersion:
                    type: integer
                  previousSecretExpiresAt:
                    type: string
                    format: date-time
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                webhookSubscriptionId: whsub_PORTFOLIO_7
                signingSecret: whsec_sandbox_once_9M4Q
                secretVersion: 3
                previousSecretExpiresAt: 2026-09-20T11:00:00Z
                version: 4
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - overlapSeconds
                - expectedVersion
              properties:
                overlapSeconds:
                  type: integer
                expectedVersion:
                  type: integer
              example:
                overlapSeconds: 3600
                expectedVersion: 3
            example:
              overlapSeconds: 3600
              expectedVersion: 3
  /v1/servicing/webhook-subscriptions/{webhookSubscriptionId}/test:
    post:
      tags:
        - Webhooks
      operationId: testWebhookSubscription
      summary: Send a test webhook
      description: Queues a signed, non-business test event through the normal delivery and retry path.
      x-permission: MANAGE_WEBHOOK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "202":
          description: Accepted for asynchronous processing.
          content:
            application/json:
              schema:
                type: object
                required:
                  - deliveryId
                  - webhookSubscriptionId
                  - status
                properties:
                  deliveryId:
                    type: string
                  webhookSubscriptionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
              example:
                deliveryId: whdel_TEST_81
                webhookSubscriptionId: whsub_PORTFOLIO_7
                status: queued
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - eventType
              properties:
                eventType:
                  type: string
              example:
                eventType: endpoint.test
            example:
              eventType: endpoint.test
  /v1/servicing/webhook-subscriptions/{webhookSubscriptionId}/deactivate:
    post:
      tags:
        - Webhooks
      operationId: deactivateWebhookSubscription
      summary: Deactivate a webhook subscription
      description: Stops new deliveries while preserving configuration and delivery history.
      x-permission: MANAGE_WEBHOOK
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - webhookSubscriptionId
                  - status
                  - version
                properties:
                  webhookSubscriptionId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                webhookSubscriptionId: whsub_PORTFOLIO_7
                status: inactive
                version: 4
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - expectedVersion
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                expectedVersion:
                  type: integer
              example:
                reasonCode: destination_retired
                expectedVersion: 3
            example:
              reasonCode: destination_retired
              expectedVersion: 3
  /v1/servicing/webhook-subscriptions/{webhookSubscriptionId}/deliveries:
    get:
      tags:
        - Webhooks
      operationId: listWebhookDeliveries
      summary: List webhook deliveries
      description: Lists event, attempt, response, timing, and next-retry metadata without response-body secrets.
      x-permission: READ_WEBHOOK
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: webhookSubscriptionId
          in: path
          required: true
          description: Stable opaque webhookSubscription identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: status
          in: query
          schema:
            type: string
          description: Filter by delivery state.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - deliveryId
                        - eventId
                        - eventType
                        - status
                        - attemptCount
                        - responseCode
                        - deliveredAt
                      properties:
                        deliveryId:
                          type: string
                        eventId:
                          type: string
                        eventType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        attemptCount:
                          type: integer
                        responseCode:
                          type: integer
                        deliveredAt:
                          type: string
                          format: date-time
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - deliveryId: whdel_PAY_81
                    eventId: evt_PAY_81
                    eventType: payment.posted
                    status: delivered
                    attemptCount: 1
                    responseCode: 204
                    deliveredAt: 2026-09-15T14:22:09Z
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/core-bindings:
    post:
      tags:
        - Core bindings
      operationId: createCoreBinding
      summary: Create a core binding
      description: Creates an isolated BYOC binding with authentication, tenant, and adapter metadata; secrets are write-only.
      x-permission: MANAGE_CORE_BINDING
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - bindingId
                  - name
                  - status
                properties:
                  bindingId:
                    type: string
                  name:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
              example:
                bindingId: core_47K
                name: Primary lending core
                status: configuration_required
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - adapterType
                - baseUrl
                - authentication
              properties:
                name:
                  type: string
                adapterType:
                  type: string
                baseUrl:
                  type: string
                authentication:
                  type: object
                  required:
                    - type
                    - secretReference
                  properties:
                    type:
                      type: string
                    secretReference:
                      type: string
              example:
                name: Primary lending core
                adapterType: custom_https
                baseUrl: https://core.example.test/lendeasy
                authentication:
                  type: oauth2_client_credentials
                  secretReference: vault://core-prod
            example:
              name: Primary lending core
              adapterType: custom_https
              baseUrl: https://core.example.test/lendeasy
              authentication:
                type: oauth2_client_credentials
                secretReference: vault://core-prod
  /v1/servicing/core-bindings/{bindingId}/capabilities:
    get:
      tags:
        - Core bindings
      operationId: getCoreCapabilities
      summary: Retrieve core capabilities
      description: Returns effective fact/action capability modes and their schema/version contract.
      x-permission: READ_CORE_BINDING
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - bindingId
                  - version
                  - effectiveAt
                  - facts
                  - actions
                properties:
                  bindingId:
                    type: string
                  version:
                    type: string
                    description: Monotonically increasing resource version.
                  effectiveAt:
                    type: string
                    format: date-time
                  facts:
                    type: object
                    required:
                      - loan.summary
                      - loan.schedule
                      - loan.apr
                    properties:
                      loan.summary:
                        type: string
                      loan.schedule:
                        type: string
                      loan.apr:
                        type: string
                  actions:
                    type: object
                    required:
                      - take_payment
                      - re_amortize
                      - apply_restriction
                    properties:
                      take_payment:
                        type: string
                      re_amortize:
                        type: string
                      apply_restriction:
                        type: string
              example:
                bindingId: core_47K
                version: 2027-04-18.3
                effectiveAt: 2027-04-18T08:00:00Z
                facts:
                  loan.summary: lms_provided
                  loan.schedule: lms_provided
                  loan.apr: unavailable
                actions:
                  take_payment: lms_provided
                  re_amortize: manual_only
                  apply_restriction: lms_provided
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
    put:
      tags:
        - Core bindings
      operationId: publishCoreCapabilities
      summary: Publish core capabilities
      description: Publishes a new effective-dated capability version after schema and enabled-workflow validation.
      x-permission: MANAGE_CORE_BINDING
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - bindingId
                  - version
                  - effectiveAt
                  - facts
                  - actions
                properties:
                  bindingId:
                    type: string
                  version:
                    type: string
                    description: Monotonically increasing resource version.
                  effectiveAt:
                    type: string
                    format: date-time
                  facts:
                    type: object
                    required:
                      - loan.summary
                      - loan.schedule
                      - loan.apr
                    properties:
                      loan.summary:
                        type: string
                      loan.schedule:
                        type: string
                      loan.apr:
                        type: string
                  actions:
                    type: object
                    required:
                      - take_payment
                      - re_amortize
                      - apply_restriction
                    properties:
                      take_payment:
                        type: string
                      re_amortize:
                        type: string
                      apply_restriction:
                        type: string
              example:
                bindingId: core_47K
                version: 2027-05-01.1
                effectiveAt: 2027-05-01T00:00:00Z
                facts:
                  loan.summary: lms_provided
                  loan.schedule: lms_provided
                  loan.apr: unavailable
                actions:
                  take_payment: lms_provided
                  re_amortize: manual_only
                  apply_restriction: lms_provided
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - effectiveAt
                - facts
                - actions
              properties:
                effectiveAt:
                  type: string
                  format: date-time
                facts:
                  type: object
                  required:
                    - loan.summary
                    - loan.schedule
                    - loan.apr
                  properties:
                    loan.summary:
                      type: string
                    loan.schedule:
                      type: string
                    loan.apr:
                      type: string
                actions:
                  type: object
                  required:
                    - take_payment
                    - re_amortize
                    - apply_restriction
                  properties:
                    take_payment:
                      type: string
                    re_amortize:
                      type: string
                    apply_restriction:
                      type: string
              example:
                effectiveAt: 2027-05-01T00:00:00Z
                facts:
                  loan.summary: lms_provided
                  loan.schedule: lms_provided
                  loan.apr: unavailable
                actions:
                  take_payment: lms_provided
                  re_amortize: manual_only
                  apply_restriction: lms_provided
            example:
              effectiveAt: 2027-05-01T00:00:00Z
              facts:
                loan.summary: lms_provided
                loan.schedule: lms_provided
                loan.apr: unavailable
              actions:
                take_payment: lms_provided
                re_amortize: manual_only
                apply_restriction: lms_provided
  /v1/servicing/core-bindings/{bindingId}/identity-mappings:
    post:
      tags:
        - Core bindings
      operationId: createIdentityMapping
      summary: Create an identity mapping
      description: Maps one stable LendEasy entity to one source entity and rejects active collisions.
      x-permission: MANAGE_CORE_BINDING
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - mappingId
                  - status
                  - entityType
                  - lendeasyId
                  - sourceId
                properties:
                  mappingId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  entityType:
                    type: string
                  lendeasyId:
                    type: string
                  sourceId:
                    type: string
              example:
                mappingId: map_HBR_4
                status: active
                entityType: loan
                lendeasyId: loan_harbor_7X2K
                sourceId: LN-0081442
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - entityType
                - lendeasyId
                - sourceId
                - sourceVersion
              properties:
                entityType:
                  type: string
                lendeasyId:
                  type: string
                sourceId:
                  type: string
                sourceVersion:
                  type: string
              example:
                entityType: loan
                lendeasyId: loan_harbor_7X2K
                sourceId: LN-0081442
                sourceVersion: acct-etag-99104
            example:
              entityType: loan
              lendeasyId: loan_harbor_7X2K
              sourceId: LN-0081442
              sourceVersion: acct-etag-99104
  /v1/servicing/core-bindings/{bindingId}/facts:
    post:
      tags:
        - Core bindings
      operationId: readCoreFacts
      summary: Read canonical core facts
      description: Requests purpose-aware canonical facts and exposes source, as-of time, observation time, and freshness.
      x-permission: READ_CORE_FACT
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - bindingId
                  - facts
                properties:
                  bindingId:
                    type: string
                  facts:
                    type: array
                    items:
                      type: object
                      required:
                        - fact
                        - entityId
                        - value
                        - source
                        - asOf
                        - observedAt
                        - freshness
                      properties:
                        fact:
                          type: string
                        entityId:
                          type: string
                        value:
                          type: object
                          required:
                            - daysPastDue
                            - amountPastDue
                          properties:
                            daysPastDue:
                              type: integer
                            amountPastDue:
                              type: string
                        source:
                          type: string
                          description: System or actor that originated the record.
                        asOf:
                          type: string
                          format: date-time
                          description: Time at which the source says the fact was true.
                        observedAt:
                          type: string
                          format: date-time
                          description: Time at which LendEasy observed the source fact.
                        freshness:
                          type: string
              example:
                bindingId: core_47K
                facts:
                  - fact: loan.delinquency
                    entityId: loan_harbor_7X2K
                    value:
                      daysPastDue: 22
                      amountPastDue: "517.14"
                    source: core_47K
                    asOf: 2027-05-01T10:11:56-07:00
                    observedAt: 2027-05-01T10:11:58-07:00
                    freshness: fresh
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - purpose
                - entities
                - facts
                - maximumAgeSeconds
              properties:
                purpose:
                  type: string
                entities:
                  type: array
                  items:
                    type: object
                    required:
                      - type
                      - id
                    properties:
                      type:
                        type: string
                      id:
                        type: string
                facts:
                  type: array
                  items:
                    type: string
                maximumAgeSeconds:
                  type: integer
              example:
                purpose: contact_eligibility
                entities:
                  - type: loan
                    id: loan_harbor_7X2K
                facts:
                  - loan.summary
                  - loan.delinquency
                  - loan.restrictions
                maximumAgeSeconds: 30
            example:
              purpose: contact_eligibility
              entities:
                - type: loan
                  id: loan_harbor_7X2K
              facts:
                - loan.summary
                - loan.delinquency
                - loan.restrictions
              maximumAgeSeconds: 30
  /v1/servicing/core-bindings/{bindingId}/actions:
    post:
      tags:
        - Core bindings
      operationId: submitCoreAction
      summary: Submit a governed core action
      description: Submits an already-governed typed action with expected source version and stable execution key.
      x-permission: EXECUTE_CORE_ACTION
      x-idempotent: true
      security:
        - oauth2:
            - servicing:write
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          description: Stable key for this one logical mutation. Reuse it for retries; reusing it with a different request returns
            409.
          schema:
            type: string
            minLength: 8
            maxLength: 128
            pattern: ^[A-Za-z0-9._:-]+$
      responses:
        "202":
          description: Accepted for asynchronous processing.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionId
                  - outcome
                  - sourceOperationId
                  - sourceVersion
                  - pollAfter
                properties:
                  actionId:
                    type: string
                    description: Stable opaque action identifier.
                  outcome:
                    type: string
                  sourceOperationId:
                    type: string
                  sourceVersion:
                    type: string
                  pollAfter:
                    type: string
              example:
                actionId: act_HBR_PMT_812
                outcome: pending_external
                sourceOperationId: PAY-99120
                sourceVersion: acct-etag-99105
                pollAfter: 2027-05-08T10:05:00-07:00
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "409":
          description: Idempotency, version, or state conflict.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/version_conflict
                title: Version Conflict
                status: 409
                code: version_conflict
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "422":
          description: Request is well-formed but violates a business rule.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/validation_error
                title: Validation Error
                status: 422
                code: validation_error
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - actionId
                - actionType
                - entity
                - expectedSourceVersion
                - parameters
                - context
              properties:
                actionId:
                  type: string
                  description: Stable opaque action identifier.
                actionType:
                  type: string
                entity:
                  type: object
                  required:
                    - loanId
                    - sourceAccountId
                  properties:
                    loanId:
                      type: string
                      description: Stable opaque loan identifier.
                    sourceAccountId:
                      type: string
                expectedSourceVersion:
                  type: string
                parameters:
                  type: object
                  description: Strict action-type-specific parameters.
                  required:
                    - amount
                    - currency
                    - effectiveDate
                    - sourceInstrumentId
                  properties:
                    amount:
                      type: string
                      description: Decimal monetary amount encoded as a string.
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                    effectiveDate:
                      type: string
                      format: date
                      description: Business-effective date in ISO 8601 format.
                    sourceInstrumentId:
                      type: string
                context:
                  type: object
                  description: Case, system-trigger, or approved-exception context for the action.
                  required:
                    - caseId
                    - reasonCode
                  properties:
                    caseId:
                      type: string
                      description: Stable opaque servicing case identifier.
                    reasonCode:
                      type: string
                      description: Configured structured reason code.
              example:
                actionId: act_HBR_PMT_812
                actionType: take_payment
                entity:
                  loanId: loan_harbor_7X2K
                  sourceAccountId: LN-0081442
                expectedSourceVersion: acct-etag-99104
                parameters:
                  amount: "517.14"
                  currency: USD
                  effectiveDate: 2027-05-08
                  sourceInstrumentId: BANK-TOKEN-204
                context:
                  caseId: case_HBR_COL_51
                  reasonCode: promise_installment
            example:
              actionId: act_HBR_PMT_812
              actionType: take_payment
              entity:
                loanId: loan_harbor_7X2K
                sourceAccountId: LN-0081442
              expectedSourceVersion: acct-etag-99104
              parameters:
                amount: "517.14"
                currency: USD
                effectiveDate: 2027-05-08
                sourceInstrumentId: BANK-TOKEN-204
              context:
                caseId: case_HBR_COL_51
                reasonCode: promise_installment
  /v1/servicing/core-bindings/{bindingId}/actions/{actionId}:
    get:
      tags:
        - Core bindings
      operationId: getCoreAction
      summary: Retrieve a core action
      description: Returns normalized acknowledgement, attempts, applied payload, source references, and reconciliation status.
      x-permission: READ_CORE_ACTION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: actionId
          in: path
          required: true
          description: Stable opaque action identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - actionId
                  - outcome
                  - sourceOperationId
                  - sourceTransactionId
                  - appliedParameters
                  - reconciliationStatus
                properties:
                  actionId:
                    type: string
                    description: Stable opaque action identifier.
                  outcome:
                    type: string
                  sourceOperationId:
                    type: string
                  sourceTransactionId:
                    type: string
                  appliedParameters:
                    type: object
                    required:
                      - amount
                      - effectiveDate
                    properties:
                      amount:
                        type: string
                        description: Decimal monetary amount encoded as a string.
                      effectiveDate:
                        type: string
                        format: date
                        description: Business-effective date in ISO 8601 format.
                  reconciliationStatus:
                    type: string
              example:
                actionId: act_HBR_PMT_812
                outcome: completed
                sourceOperationId: PAY-99120
                sourceTransactionId: TX-77182
                appliedParameters:
                  amount: "517.14"
                  effectiveDate: 2027-05-08
                reconciliationStatus: matched
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/servicing/core-bindings/{bindingId}/reconciliation:
    get:
      tags:
        - Core bindings
      operationId: listCoreBindingDrift
      summary: List core-binding drift
      description: Lists identity, fact, action, acknowledgement, and source-to-ledger divergence.
      x-permission: READ_RECONCILIATION
      x-idempotent: false
      security:
        - oauth2:
            - servicing:read
      parameters:
        - name: bindingId
          in: path
          required: true
          description: Stable opaque binding identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: severity
          in: query
          schema:
            type: string
          description: Filter by drift severity.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - driftId
                        - type
                        - severity
                        - actionId
                        - status
                        - detectedAt
                      properties:
                        driftId:
                          type: string
                        type:
                          type: string
                        severity:
                          type: string
                        actionId:
                          type: string
                          description: Stable opaque action identifier.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        detectedAt:
                          type: string
                          format: date-time
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - driftId: drift_CORE_8
                    type: action_completed_balance_unchanged
                    severity: critical
                    actionId: act_HBR_PMT_812
                    status: open
                    detectedAt: 2027-05-08T10:20:00-07:00
                nextCursor: null
                hasMore: false
        "401":
          description: Token missing, invalid, or expired.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/unauthorized
                title: Unauthorized
                status: 401
                code: unauthorized
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "403":
          description: Token lacks the required permission.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/forbidden
                title: Forbidden
                status: 403
                code: forbidden
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "404":
          description: Resource not found in the caller tenant.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/not_found
                title: Not Found
                status: 404
                code: not_found
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
        "429":
          description: The client exceeded its current rate budget; retry after the indicated delay.
          content:
            application/problem+json:
              schema:
                type: object
                required:
                  - type
                  - title
                  - status
                  - code
                  - detail
                  - requestId
                properties:
                  type:
                    type: string
                  title:
                    type: string
                  status:
                    type: integer
                    description: Current normalized lifecycle state.
                  code:
                    type: string
                  detail:
                    type: string
                  requestId:
                    type: string
              example:
                type: https://docs.lendeasy.ai/errors/rate_limited
                title: Rate Limited
                status: 429
                code: rate_limited
                detail: The request could not be applied.
                requestId: req_01J2R8M6YQ3C7K2N
  /v1/customers:
    post:
      tags:
        - Customers
      operationId: createCustomer
      summary: Create a customer
      description: Creates a customer profile and, in the same request only, optional initial addresses, contact points,
        identifiers, and consents. The profile is a closed INDIVIDUAL or CORPORATE union; after creation the profile
        changes through PUT and each child collection changes through its own focused route.
      x-permission: CREATE_LMS_CUSTOMER
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 412
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - profile
                - addresses
                - contactPoints
              properties:
                profile:
                  type: object
                  required:
                    - customerType
                    - firstName
                    - lastName
                    - dateOfBirth
                    - externalId
                  properties:
                    customerType:
                      type: string
                    firstName:
                      type: string
                    lastName:
                      type: string
                    dateOfBirth:
                      type: string
                    externalId:
                      type: string
                      description: Caller-controlled identifier unique within the tenant and resource type.
                addresses:
                  type: array
                  items:
                    type: object
                    required:
                      - addressType
                      - line1
                      - city
                      - stateCode
                      - postalCode
                      - country
                      - isPrimary
                    properties:
                      addressType:
                        type: string
                      line1:
                        type: string
                      city:
                        type: string
                      stateCode:
                        type: string
                      postalCode:
                        type: string
                      country:
                        type: string
                      isPrimary:
                        type: boolean
                contactPoints:
                  type: array
                  items:
                    type: object
                    required:
                      - contactType
                      - value
                      - isPrimary
                    properties:
                      contactType:
                        type: string
                      value:
                        type: string
                      isPrimary:
                        type: boolean
              example:
                profile:
                  customerType: INDIVIDUAL
                  firstName: Maya
                  lastName: Chen
                  dateOfBirth: 1991-11-04
                  externalId: crm-person-81042
                addresses:
                  - addressType: PRIMARY_RESIDENCE
                    line1: 428 Alder Way
                    city: Sacramento
                    stateCode: US-CA
                    postalCode: "95814"
                    country: US
                    isPrimary: true
                contactPoints:
                  - contactType: EMAIL
                    value: maya.chen@example.test
                    isPrimary: true
            example:
              profile:
                customerType: INDIVIDUAL
                firstName: Maya
                lastName: Chen
                dateOfBirth: 1991-11-04
                externalId: crm-person-81042
              addresses:
                - addressType: PRIMARY_RESIDENCE
                  line1: 428 Alder Way
                  city: Sacramento
                  stateCode: US-CA
                  postalCode: "95814"
                  country: US
                  isPrimary: true
              contactPoints:
                - contactType: EMAIL
                  value: maya.chen@example.test
                  isPrimary: true
    get:
      tags:
        - Customers
      operationId: listCustomers
      summary: List customers
      description: Returns masked customer summaries ordered by last modification, newest first, using limit/offset paging.
        Summaries never include street, contact, or identifier values.
      x-permission: READ_LMS_CUSTOMER
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - limit
                  - offset
                  - items
                properties:
                  limit:
                    type: integer
                  offset:
                    type: integer
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - customerId
                        - status
                        - customerType
                        - displayName
                        - lastModifiedAt
                      properties:
                        customerId:
                          type: string
                          description: Stable opaque customer identifier.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        customerType:
                          type: string
                        displayName:
                          type: string
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                limit: 50
                offset: 0
                items:
                  - customerId: "412"
                    status: ACTIVE
                    customerType: INDIVIDUAL
                    displayName: Maya Chen
                    lastModifiedAt: 2026-09-15T14:22:08Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}:
    get:
      tags:
        - Customers
      operationId: getCustomer
      summary: Retrieve a customer
      description: "Returns the customer aggregate: profile plus current addresses, masked contact points, consents, and
        masked identifiers. This is the only current-state read for those child collections; removed children are
        omitted."
      x-permission: READ_LMS_CUSTOMER
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - customerId
                  - status
                  - profile
                  - addresses
                  - contactPoints
                  - consents
                  - identifiers
                  - createdAt
                  - lastModifiedAt
                properties:
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  profile:
                    type: object
                    required:
                      - customerType
                      - firstName
                      - lastName
                      - dateOfBirth
                      - externalId
                      - activationDate
                    properties:
                      customerType:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                      dateOfBirth:
                        type: string
                      externalId:
                        type: string
                        description: Caller-controlled identifier unique within the tenant and resource type.
                      activationDate:
                        type: string
                        format: date
                  addresses:
                    type: array
                    items:
                      type: object
                      required:
                        - addressId
                        - addressType
                        - line1
                        - city
                        - stateCode
                        - postalCode
                        - country
                        - isPrimary
                        - isSecondary
                        - status
                        - verificationState
                        - deliverabilityStatus
                      properties:
                        addressId:
                          type: integer
                        addressType:
                          type: string
                        line1:
                          type: string
                        city:
                          type: string
                        stateCode:
                          type: string
                        postalCode:
                          type: string
                        country:
                          type: string
                        isPrimary:
                          type: boolean
                        isSecondary:
                          type: boolean
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        verificationState:
                          type: string
                        deliverabilityStatus:
                          type: string
                  contactPoints:
                    type: array
                    items:
                      type: object
                      required:
                        - contactPointId
                        - contactType
                        - maskedDisplay
                        - isPrimary
                        - isSecondary
                        - status
                        - deliverabilityStatus
                      properties:
                        contactPointId:
                          type: integer
                        contactType:
                          type: string
                        maskedDisplay:
                          type: string
                        isPrimary:
                          type: boolean
                        isSecondary:
                          type: boolean
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        deliverabilityStatus:
                          type: string
                  consents:
                    type: array
                    items:
                      type: object
                      required:
                        - consentId
                        - consentType
                        - status
                        - capturedAt
                        - captureMethod
                      properties:
                        consentId:
                          type: integer
                        consentType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        capturedAt:
                          type: string
                          format: date-time
                        captureMethod:
                          type: string
                  identifiers:
                    type: array
                    items:
                      type: object
                      required:
                        - identifierId
                        - identifierType
                        - maskedDisplay
                        - verificationState
                        - status
                      properties:
                        identifierId:
                          type: integer
                        identifierType:
                          type: string
                        maskedDisplay:
                          type: string
                        verificationState:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                customerId: "412"
                status: ACTIVE
                profile:
                  customerType: INDIVIDUAL
                  firstName: Maya
                  lastName: Chen
                  dateOfBirth: 1991-11-04
                  externalId: crm-person-81042
                  activationDate: 2026-08-01
                addresses:
                  - addressId: 311
                    addressType: PRIMARY_RESIDENCE
                    line1: 428 Alder Way
                    city: Sacramento
                    stateCode: US-CA
                    postalCode: "95814"
                    country: US
                    isPrimary: true
                    isSecondary: false
                    status: ACTIVE
                    verificationState: UNVERIFIED
                    deliverabilityStatus: UNKNOWN
                contactPoints:
                  - contactPointId: 512
                    contactType: EMAIL
                    maskedDisplay: m•••@example.test
                    isPrimary: true
                    isSecondary: false
                    status: UNVERIFIED
                    deliverabilityStatus: UNKNOWN
                consents:
                  - consentId: 71
                    consentType: AUTODIALED_CALL
                    status: GRANTED
                    capturedAt: 2026-08-01T17:05:00Z
                    captureMethod: BORROWER_PORTAL
                identifiers:
                  - identifierId: 66
                    identifierType: SSN
                    maskedDisplay: •••-••-4821
                    verificationState: UNVERIFIED
                    status: ACTIVE
                createdAt: 2026-08-01T17:04:11Z
                lastModifiedAt: 2026-09-15T14:22:08Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Customers
      operationId: updateCustomerProfile
      summary: Update a customer profile
      description: "Merge-updates profile fields only: supplied fields change, omitted fields stay, and an explicit null
        clears a nullable field. customerType is immutable and child collections are rejected here; use the focused
        address, contact-point, identifier, and consent routes."
      x-permission: UPDATE_LMS_CUSTOMER_PROFILE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - lastName
                    properties:
                      lastName:
                        type: string
              example:
                resourceId: 412
                changes:
                  lastName: Chen-Liu
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - lastName
              properties:
                lastName:
                  type: string
              example:
                lastName: Chen-Liu
            example:
              lastName: Chen-Liu
  /v1/customers/{customerId}/sensitive:
    get:
      tags:
        - Customers
      operationId: getCustomerSensitive
      summary: Retrieve sensitive customer values
      description: Returns complete identifier values, raw contact values, and consent evidence references. Requires both the
        ordinary and the sensitive read permission; every call is audited and the response is never cached.
      x-permission: READ_LMS_CUSTOMER & READ_LMS_CUSTOMER_SENSITIVE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - customerId
                  - identifiers
                  - contactPoints
                  - consents
                properties:
                  customerId:
                    type: string
                    description: Stable opaque customer identifier.
                  identifiers:
                    type: array
                    items:
                      type: object
                      required:
                        - identifierId
                        - identifierType
                        - value
                        - verificationState
                        - status
                      properties:
                        identifierId:
                          type: integer
                        identifierType:
                          type: string
                        value:
                          type: string
                        verificationState:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                  contactPoints:
                    type: array
                    items:
                      type: object
                      required:
                        - contactPointId
                        - contactType
                        - value
                        - status
                        - carrierVerified
                        - deliverabilityStatus
                      properties:
                        contactPointId:
                          type: integer
                        contactType:
                          type: string
                        value:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        carrierVerified:
                          type: boolean
                        deliverabilityStatus:
                          type: string
                  consents:
                    type: array
                    items:
                      type: object
                      required:
                        - consentId
                        - consentType
                        - status
                        - captureMethod
                        - evidenceRef
                      properties:
                        consentId:
                          type: integer
                        consentType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        captureMethod:
                          type: string
                        evidenceRef:
                          type: string
              example:
                customerId: "412"
                identifiers:
                  - identifierId: 66
                    identifierType: SSN
                    value: "601114821"
                    verificationState: VERIFIED
                    status: ACTIVE
                contactPoints:
                  - contactPointId: 512
                    contactType: EMAIL
                    value: maya.chen@example.test
                    status: VERIFIED
                    carrierVerified: false
                    deliverabilityStatus: DELIVERABLE
                consents:
                  - consentId: 71
                    consentType: AUTODIALED_CALL
                    status: GRANTED
                    captureMethod: BORROWER_PORTAL
                    evidenceRef: evd_CONSENT_41
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/lookup:
    post:
      tags:
        - Customers
      operationId: lookupCustomerByIdentifier
      summary: Look up a customer by exact identifier
      description: Finds customers whose current identifier exactly equals the supplied value. A POST body keeps the value out
        of URLs and logs; the route accepts no Idempotency-Key, is audited, and answers with masked summaries only. An
        empty result never reveals whether a hidden match exists.
      x-permission: READ_LMS_CUSTOMER & READ_LMS_CUSTOMER_SENSITIVE
      x-idempotent: false
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - customerId
                        - status
                        - customerType
                        - displayName
                        - lastModifiedAt
                      properties:
                        customerId:
                          type: string
                          description: Stable opaque customer identifier.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        customerType:
                          type: string
                        displayName:
                          type: string
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - customerId: "412"
                    status: ACTIVE
                    customerType: INDIVIDUAL
                    displayName: Maya Chen
                    lastModifiedAt: 2026-09-15T14:22:08Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - identifierType
                - value
              properties:
                identifierType:
                  type: string
                value:
                  type: string
              example:
                identifierType: SSN
                value: "601114821"
            example:
              identifierType: SSN
              value: "601114821"
  /v1/customers/{customerId}/history:
    get:
      tags:
        - Customers
      operationId: listCustomerHistory
      summary: List customer history
      description: Returns the append-only change ledger for the customer and its children, newest first, with cursor paging.
        Without the sensitive read permission, protected values appear as redacted placeholders.
      x-permission: READ_LMS_CUSTOMER_HISTORY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum events to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: categories
          in: query
          required: false
          description: Repeatable subject category filter.
          schema:
            type: string
            enum:
              - PROFILE
              - ADDRESS
              - CONTACT_POINT
              - CONSENT
              - IDENTIFIER
              - DOCUMENT
              - NOTE
              - FORM_ENTRY
              - RESTRICTION
              - LOAN_PARTY
        - name: actions
          in: query
          required: false
          description: Repeatable action filter within the selected categories.
          schema:
            type: string
        - name: occurredFrom
          in: query
          required: false
          description: Inclusive lower bound; supply with occurredTo.
          schema:
            type: string
            format: date-time
        - name: occurredTo
          in: query
          required: false
          description: Exclusive upper bound; supply with occurredFrom.
          schema:
            type: string
            format: date-time
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - nextCursor
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - historyId
                        - occurredAt
                        - category
                        - action
                        - subject
                        - summary
                        - changes
                        - actor
                        - correlationId
                      properties:
                        historyId:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        category:
                          type: string
                        action:
                          type: string
                        subject:
                          type: object
                          required:
                            - type
                            - ref
                            - href
                          properties:
                            type:
                              type: string
                            ref:
                              type: string
                            href:
                              type: string
                        summary:
                          type: string
                        changes:
                          type: object
                          required:
                            - canReceiveSms
                          properties:
                            canReceiveSms:
                              type: object
                              required:
                                - before
                                - after
                              properties:
                                before:
                                  type: boolean
                                after:
                                  type: boolean
                        actor:
                          type: object
                          required:
                            - type
                            - ref
                            - username
                            - firstName
                            - lastName
                          properties:
                            type:
                              type: string
                            ref:
                              type: string
                            username:
                              type: string
                            firstName:
                              type: string
                            lastName:
                              type: string
                        correlationId:
                          type: string
                  nextCursor:
                    type: string
              example:
                items:
                  - historyId: h_01JZ7M5K9Y
                    occurredAt: 2026-09-15T14:22:08Z
                    category: CONTACT_POINT
                    action: UPDATE
                    subject:
                      type: CONTACT_POINT
                      ref: "512"
                      href: /v1/customers/412
                    summary: Contact point updated
                    changes:
                      canReceiveSms:
                        before: false
                        after: true
                    actor:
                      type: STAFF
                      ref: "9"
                      username: ana.alvarez
                      firstName: Ana
                      lastName: Alvarez
                    correlationId: corr_01JZ7M5K9X
                nextCursor: null
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/history/{historyId}:
    get:
      tags:
        - Customers
      operationId: getCustomerHistoryEvent
      summary: Retrieve a history event
      description: Returns one history event with its field-level before/after changes, actor, and correlation id linking
        sibling events written by the same command.
      x-permission: READ_LMS_CUSTOMER_HISTORY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: historyId
          in: path
          required: true
          description: Stable opaque history identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - historyId
                  - occurredAt
                  - category
                  - action
                  - subject
                  - summary
                  - changes
                  - actor
                  - correlationId
                properties:
                  historyId:
                    type: string
                  occurredAt:
                    type: string
                    format: date-time
                  category:
                    type: string
                  action:
                    type: string
                  subject:
                    type: object
                    required:
                      - type
                      - ref
                      - href
                    properties:
                      type:
                        type: string
                      ref:
                        type: string
                      href:
                        type: string
                  summary:
                    type: string
                  changes:
                    type: object
                    required:
                      - canReceiveSms
                    properties:
                      canReceiveSms:
                        type: object
                        required:
                          - before
                          - after
                        properties:
                          before:
                            type: boolean
                          after:
                            type: boolean
                  actor:
                    type: object
                    required:
                      - type
                      - ref
                      - username
                      - firstName
                      - lastName
                    properties:
                      type:
                        type: string
                      ref:
                        type: string
                      username:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                  correlationId:
                    type: string
              example:
                historyId: h_01JZ7M5K9Y
                occurredAt: 2026-09-15T14:22:08Z
                category: CONTACT_POINT
                action: UPDATE
                subject:
                  type: CONTACT_POINT
                  ref: "512"
                  href: /v1/customers/412
                summary: Contact point updated
                changes:
                  canReceiveSms:
                    before: false
                    after: true
                actor:
                  type: STAFF
                  ref: "9"
                  username: ana.alvarez
                  firstName: Ana
                  lastName: Alvarez
                correlationId: corr_01JZ7M5K9X
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/addresses:
    post:
      tags:
        - Addresses
      operationId: createCustomerAddress
      summary: Add a customer address
      description: Adds a typed address. addressType is immutable; PRIMARY_RESIDENCE, MAILING, LEGAL_NOTICE, and STATEMENT
        allow one active address each. country is ISO 3166-1 alpha-2 and stateCode is the full ISO 3166-2 code matching
        it. Verification, deliverability, and geolocation fields are accepted only from trusted integrations.
      x-permission: UPDATE_LMS_CUSTOMER_ADDRESS
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 312
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - addressType
                - line1
                - city
                - stateCode
                - postalCode
                - country
              properties:
                addressType:
                  type: string
                line1:
                  type: string
                city:
                  type: string
                stateCode:
                  type: string
                postalCode:
                  type: string
                country:
                  type: string
              example:
                addressType: MAILING
                line1: PO Box 210
                city: Sacramento
                stateCode: US-CA
                postalCode: "95812"
                country: US
            example:
              addressType: MAILING
              line1: PO Box 210
              city: Sacramento
              stateCode: US-CA
              postalCode: "95812"
              country: US
  /v1/customers/{customerId}/addresses/{addressId}:
    put:
      tags:
        - Addresses
      operationId: updateCustomerAddress
      summary: Update a customer address
      description: Merge-updates address fields; addressType is immutable. The change is recorded in customer history with
        field-level before/after values.
      x-permission: UPDATE_LMS_CUSTOMER_ADDRESS
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: addressId
          in: path
          required: true
          description: Stable opaque address identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - line2
                    properties:
                      line2:
                        type: string
              example:
                resourceId: 311
                changes:
                  line2: Unit 4
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - line2
              properties:
                line2:
                  type: string
              example:
                line2: Unit 4
            example:
              line2: Unit 4
    delete:
      tags:
        - Addresses
      operationId: removeCustomerAddress
      summary: Remove a customer address
      description: Soft-removes the address with no request body. The row leaves the aggregate read but its full history is
        retained.
      x-permission: UPDATE_LMS_CUSTOMER_ADDRESS
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: addressId
          in: path
          required: true
          description: Stable opaque address identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 311
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/customers/{customerId}/addresses/{addressId}/history:
    get:
      tags:
        - Addresses
      operationId: listCustomerAddressHistory
      summary: List address history
      description: Returns the change ledger for one address with cursor paging; the category is fixed to ADDRESS.
      x-permission: READ_LMS_CUSTOMER_HISTORY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: addressId
          in: path
          required: true
          description: Stable opaque address identifier.
          schema:
            type: string
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum events to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - nextCursor
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - historyId
                        - occurredAt
                        - category
                        - action
                        - subject
                        - summary
                        - correlationId
                      properties:
                        historyId:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        category:
                          type: string
                        action:
                          type: string
                        subject:
                          type: object
                          required:
                            - type
                            - ref
                            - href
                          properties:
                            type:
                              type: string
                            ref:
                              type: string
                            href:
                              type: string
                        summary:
                          type: string
                        correlationId:
                          type: string
                  nextCursor:
                    type: string
              example:
                items:
                  - historyId: h_01JZ7M5KA1
                    occurredAt: 2026-08-01T17:04:11Z
                    category: ADDRESS
                    action: CREATE
                    subject:
                      type: ADDRESS
                      ref: "311"
                      href: /v1/customers/412
                    summary: Address created
                    correlationId: corr_01JZ7M5K9X
                nextCursor: null
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/contact-points:
    post:
      tags:
        - Contact points
      operationId: createCustomerContactPoint
      summary: Add a customer contact point
      description: Adds an EMAIL or PHONE contact point. New values default to UNVERIFIED; canReceiveSms is explicit texting
        permission (default false) and requires smsPermissionChangedAt whenever supplied. Verification, carrier, and
        deliverability results are accepted only from trusted integrations.
      x-permission: UPDATE_LMS_CUSTOMER_CONTACT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 513
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - contactType
                - value
                - phoneType
                - canReceiveSms
                - smsPermissionChangedAt
              properties:
                contactType:
                  type: string
                value:
                  type: string
                phoneType:
                  type: string
                canReceiveSms:
                  type: boolean
                smsPermissionChangedAt:
                  type: string
                  format: date-time
              example:
                contactType: PHONE
                value: "+19165550126"
                phoneType: MOBILE
                canReceiveSms: true
                smsPermissionChangedAt: 2026-08-01T17:05:00Z
            example:
              contactType: PHONE
              value: "+19165550126"
              phoneType: MOBILE
              canReceiveSms: true
              smsPermissionChangedAt: 2026-08-01T17:05:00Z
  /v1/customers/{customerId}/contact-points/{contactPointId}:
    put:
      tags:
        - Contact points
      operationId: updateCustomerContactPoint
      summary: Update a customer contact point
      description: Merge-updates the contact point; contactType is immutable. Changing a phone value resets texting permission
        and verification state unless fresh trusted results arrive in the same change.
      x-permission: UPDATE_LMS_CUSTOMER_CONTACT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: contactPointId
          in: path
          required: true
          description: Stable opaque contactPoint identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - canReceiveSms
                    properties:
                      canReceiveSms:
                        type: boolean
              example:
                resourceId: 513
                changes:
                  canReceiveSms: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - canReceiveSms
                - smsPermissionChangedAt
              properties:
                canReceiveSms:
                  type: boolean
                smsPermissionChangedAt:
                  type: string
                  format: date-time
              example:
                canReceiveSms: false
                smsPermissionChangedAt: 2027-05-01T10:32:00Z
            example:
              canReceiveSms: false
              smsPermissionChangedAt: 2027-05-01T10:32:00Z
    delete:
      tags:
        - Contact points
      operationId: removeCustomerContactPoint
      summary: Remove a customer contact point
      description: Soft-removes the contact point with no request body; history is retained.
      x-permission: UPDATE_LMS_CUSTOMER_CONTACT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: contactPointId
          in: path
          required: true
          description: Stable opaque contactPoint identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 513
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/customers/{customerId}/identifiers:
    post:
      tags:
        - Customer identifiers
      operationId: createCustomerIdentifier
      summary: Add a customer identifier
      description: Attaches a government identifier. The complete value is supplied once, stored normalized, and masked on
        every ordinary read; SSN and EIN normalize to nine digits. Verification state is set only by trusted
        integrations. INDIVIDUAL customers use SSN, DRIVER_LICENSE, or PASSPORT; CORPORATE customers use EIN.
      x-permission: UPDATE_LMS_CUSTOMER_IDENTIFIER
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 66
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - identifierType
                - value
              properties:
                identifierType:
                  type: string
                value:
                  type: string
              example:
                identifierType: SSN
                value: 601-11-4821
            example:
              identifierType: SSN
              value: 601-11-4821
  /v1/customers/{customerId}/identifiers/{identifierId}:
    put:
      tags:
        - Customer identifiers
      operationId: updateCustomerIdentifier
      summary: Update a customer identifier
      description: Merge-updates the identifier; identifierType is immutable. Complete values never appear in command audit,
        history, events, or logs.
      x-permission: UPDATE_LMS_CUSTOMER_IDENTIFIER
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: identifierId
          in: path
          required: true
          description: Stable opaque identifier identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - evidenceRef
                    properties:
                      evidenceRef:
                        type: string
              example:
                resourceId: 66
                changes:
                  evidenceRef: evd_IDV_81
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - evidenceRef
              properties:
                evidenceRef:
                  type: string
              example:
                evidenceRef: evd_IDV_81
            example:
              evidenceRef: evd_IDV_81
    delete:
      tags:
        - Customer identifiers
      operationId: removeCustomerIdentifier
      summary: Remove a customer identifier
      description: Soft-removes the identifier with no request body; masked history is retained.
      x-permission: UPDATE_LMS_CUSTOMER_IDENTIFIER
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: identifierId
          in: path
          required: true
          description: Stable opaque identifier identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 66
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/customers/{customerId}/consents:
    post:
      tags:
        - Consents
      operationId: createConsent
      summary: Record a consent
      description: "Records a granted consent from the closed catalog: ELECTRONIC_COMMUNICATION, AUTODIALED_CALL,
        ARTIFICIAL_VOICE, or UNUSUAL_TIME. Capture time and method are required; evidence and legal-basis references are
        optional."
      x-permission: UPDATE_LMS_CUSTOMER_CONSENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 71
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - consentType
                - capturedAt
                - captureMethod
                - evidenceRef
              properties:
                consentType:
                  type: string
                capturedAt:
                  type: string
                  format: date-time
                captureMethod:
                  type: string
                evidenceRef:
                  type: string
              example:
                consentType: AUTODIALED_CALL
                capturedAt: 2026-08-01T17:05:00Z
                captureMethod: BORROWER_PORTAL
                evidenceRef: evd_CONSENT_41
            example:
              consentType: AUTODIALED_CALL
              capturedAt: 2026-08-01T17:05:00Z
              captureMethod: BORROWER_PORTAL
              evidenceRef: evd_CONSENT_41
  /v1/customers/{customerId}/consents/{consentId}/revoke:
    post:
      tags:
        - Consents
      operationId: revokeConsent
      summary: Revoke a consent
      description: Revokes the consent with no request body; the server derives the effective time. The original grant and its
        evidence remain immutable in history.
      x-permission: UPDATE_LMS_CUSTOMER_CONSENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: consentId
          in: path
          required: true
          description: Stable opaque consent identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 71
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/customers/{customerId}/payment-instruments:
    post:
      tags:
        - Payment instruments
      operationId: createCustomerPaymentInstrument
      summary: Add a customer payment instrument
      description: Attaches a processor-tokenized customer instrument. providerTokenRef must be a vault token; raw account,
        routing, or card numbers are rejected. The server resolves the token to derive the masked display, rail
        capabilities, and type. New instruments start UNVERIFIED; verification completes through provider events, never
        through a public route.
      x-permission: CREATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 704
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - instrumentType
                - providerTokenRef
                - authorizationRef
              properties:
                instrumentType:
                  type: string
                providerTokenRef:
                  type: string
                authorizationRef:
                  type: string
              example:
                instrumentType: ACH_BANK
                providerTokenRef: vault:ach:tok_sandbox_bank_44
                authorizationRef: evd_BANK_AUTH_11
            example:
              instrumentType: ACH_BANK
              providerTokenRef: vault:ach:tok_sandbox_bank_44
              authorizationRef: evd_BANK_AUTH_11
    get:
      tags:
        - Payment instruments
      operationId: listCustomerPaymentInstruments
      summary: List customer payment instruments
      description: Lists masked instruments with verification and validation state; tokens and authorization references are
        never returned on masked reads.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Filter by instrument status.
          schema:
            type: string
            enum:
              - ACTIVE
              - INACTIVE
        - name: instrumentType
          in: query
          required: false
          description: Filter by instrument type.
          schema:
            type: string
            enum:
              - ACH_BANK
              - CARD
        - name: verificationState
          in: query
          required: false
          description: Filter by verification state.
          schema:
            type: string
            enum:
              - UNVERIFIED
              - VERIFIED
              - FAILED
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - instrumentId
                        - instrumentType
                        - maskedDisplay
                        - railCapabilities
                        - verificationState
                        - accountValidationStatus
                        - status
                        - createdAt
                        - lastModifiedAt
                      properties:
                        instrumentId:
                          type: integer
                        instrumentType:
                          type: string
                        maskedDisplay:
                          type: string
                        railCapabilities:
                          type: array
                          items:
                            type: string
                        verificationState:
                          type: string
                        accountValidationStatus:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - instrumentId: 704
                    instrumentType: ACH_BANK
                    maskedDisplay: ••6789
                    railCapabilities:
                      - ACH
                    verificationState: VERIFIED
                    accountValidationStatus: VALIDATED
                    status: ACTIVE
                    createdAt: 2026-08-11T16:10:00Z
                    lastModifiedAt: 2026-08-11T16:12:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/payment-instruments/{instrumentId}:
    get:
      tags:
        - Payment instruments
      operationId: getCustomerPaymentInstrument
      summary: Retrieve a payment instrument
      description: Returns masked metadata and lifecycle state. No public route returns raw account or card values; they are
        never stored.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - instrumentId
                  - instrumentType
                  - maskedDisplay
                  - railCapabilities
                  - verificationState
                  - accountValidationStatus
                  - status
                  - createdAt
                  - lastModifiedAt
                properties:
                  instrumentId:
                    type: integer
                  instrumentType:
                    type: string
                  maskedDisplay:
                    type: string
                  railCapabilities:
                    type: array
                    items:
                      type: string
                  verificationState:
                    type: string
                  accountValidationStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                instrumentId: 704
                instrumentType: ACH_BANK
                maskedDisplay: ••6789
                railCapabilities:
                  - ACH
                verificationState: VERIFIED
                accountValidationStatus: VALIDATED
                status: ACTIVE
                createdAt: 2026-08-11T16:10:00Z
                lastModifiedAt: 2026-08-11T16:12:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Payment instruments
      operationId: updateCustomerPaymentInstrument
      summary: Update a payment instrument
      description: Replaces the vault token or authorization reference. A new token must resolve to the same immutable
        instrument type and refreshes the masked display and rail capabilities.
      x-permission: UPDATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - providerTokenRef
                    properties:
                      providerTokenRef:
                        type: string
              example:
                resourceId: 704
                changes:
                  providerTokenRef: vault:ach:tok_sandbox_bank_45
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - providerTokenRef
              properties:
                providerTokenRef:
                  type: string
              example:
                providerTokenRef: vault:ach:tok_sandbox_bank_45
            example:
              providerTokenRef: vault:ach:tok_sandbox_bank_45
  /v1/customers/{customerId}/payment-instruments/{instrumentId}/deactivate:
    post:
      tags:
        - Payment instruments
      operationId: deactivateCustomerPaymentInstrument
      summary: Deactivate a payment instrument
      description: "Stops future use and cascades dependent autopay enrollments into review. Idempotent: deactivating an
        inactive instrument is a no-op."
      x-permission: UPDATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 704
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: CUSTOMER_REQUEST
                comment: Account closed at bank.
            example:
              reasonCode: CUSTOMER_REQUEST
              comment: Account closed at bank.
  /v1/customers/{customerId}/payment-instruments/{instrumentId}/sensitive:
    get:
      tags:
        - Payment instruments
      operationId: getCustomerPaymentInstrumentSensitive
      summary: Retrieve sensitive instrument references
      description: Returns the masked fields plus the vault token and authorization reference. Requires both read permissions;
        every call is audited and the response is never cached.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT & READ_LMS_PAYMENT_INSTRUMENT_SENSITIVE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - instrumentId
                  - instrumentType
                  - maskedDisplay
                  - railCapabilities
                  - verificationState
                  - accountValidationStatus
                  - status
                  - createdAt
                  - lastModifiedAt
                  - providerTokenRef
                  - authorizationRef
                properties:
                  instrumentId:
                    type: integer
                  instrumentType:
                    type: string
                  maskedDisplay:
                    type: string
                  railCapabilities:
                    type: array
                    items:
                      type: string
                  verificationState:
                    type: string
                  accountValidationStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
                  providerTokenRef:
                    type: string
                  authorizationRef:
                    type: string
              example:
                instrumentId: 704
                instrumentType: ACH_BANK
                maskedDisplay: ••6789
                railCapabilities:
                  - ACH
                verificationState: VERIFIED
                accountValidationStatus: VALIDATED
                status: ACTIVE
                createdAt: 2026-08-11T16:10:00Z
                lastModifiedAt: 2026-08-11T16:12:00Z
                providerTokenRef: vault:ach:tok_sandbox_bank_44
                authorizationRef: evd_BANK_AUTH_11
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/external-parties/{partyId}/payment-instruments:
    post:
      tags:
        - Payment instruments
      operationId: createExternalPartyPaymentInstrument
      summary: Add an external-party payment instrument
      description: Attaches a processor-tokenized external-party instrument. providerTokenRef must be a vault token; raw
        account, routing, or card numbers are rejected. The server resolves the token to derive the masked display, rail
        capabilities, and type. New instruments start UNVERIFIED; verification completes through provider events, never
        through a public route.
      x-permission: CREATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 704
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - instrumentType
                - providerTokenRef
                - authorizationRef
              properties:
                instrumentType:
                  type: string
                providerTokenRef:
                  type: string
                authorizationRef:
                  type: string
              example:
                instrumentType: ACH_BANK
                providerTokenRef: vault:ach:tok_sandbox_bank_44
                authorizationRef: evd_BANK_AUTH_11
            example:
              instrumentType: ACH_BANK
              providerTokenRef: vault:ach:tok_sandbox_bank_44
              authorizationRef: evd_BANK_AUTH_11
    get:
      tags:
        - Payment instruments
      operationId: listExternalPartyPaymentInstruments
      summary: List external-party payment instruments
      description: Lists masked instruments with verification and validation state; tokens and authorization references are
        never returned on masked reads.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Filter by instrument status.
          schema:
            type: string
            enum:
              - ACTIVE
              - INACTIVE
        - name: instrumentType
          in: query
          required: false
          description: Filter by instrument type.
          schema:
            type: string
            enum:
              - ACH_BANK
              - CARD
        - name: verificationState
          in: query
          required: false
          description: Filter by verification state.
          schema:
            type: string
            enum:
              - UNVERIFIED
              - VERIFIED
              - FAILED
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - instrumentId
                        - instrumentType
                        - maskedDisplay
                        - railCapabilities
                        - verificationState
                        - accountValidationStatus
                        - status
                        - createdAt
                        - lastModifiedAt
                      properties:
                        instrumentId:
                          type: integer
                        instrumentType:
                          type: string
                        maskedDisplay:
                          type: string
                        railCapabilities:
                          type: array
                          items:
                            type: string
                        verificationState:
                          type: string
                        accountValidationStatus:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - instrumentId: 704
                    instrumentType: ACH_BANK
                    maskedDisplay: ••6789
                    railCapabilities:
                      - ACH
                    verificationState: VERIFIED
                    accountValidationStatus: VALIDATED
                    status: ACTIVE
                    createdAt: 2026-08-11T16:10:00Z
                    lastModifiedAt: 2026-08-11T16:12:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/external-parties/{partyId}/payment-instruments/{instrumentId}:
    get:
      tags:
        - Payment instruments
      operationId: getExternalPartyPaymentInstrument
      summary: Retrieve a payment instrument
      description: Returns masked metadata and lifecycle state. No public route returns raw account or card values; they are
        never stored.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - instrumentId
                  - instrumentType
                  - maskedDisplay
                  - railCapabilities
                  - verificationState
                  - accountValidationStatus
                  - status
                  - createdAt
                  - lastModifiedAt
                properties:
                  instrumentId:
                    type: integer
                  instrumentType:
                    type: string
                  maskedDisplay:
                    type: string
                  railCapabilities:
                    type: array
                    items:
                      type: string
                  verificationState:
                    type: string
                  accountValidationStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                instrumentId: 704
                instrumentType: ACH_BANK
                maskedDisplay: ••6789
                railCapabilities:
                  - ACH
                verificationState: VERIFIED
                accountValidationStatus: VALIDATED
                status: ACTIVE
                createdAt: 2026-08-11T16:10:00Z
                lastModifiedAt: 2026-08-11T16:12:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Payment instruments
      operationId: updateExternalPartyPaymentInstrument
      summary: Update a payment instrument
      description: Replaces the vault token or authorization reference. A new token must resolve to the same immutable
        instrument type and refreshes the masked display and rail capabilities.
      x-permission: UPDATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - providerTokenRef
                    properties:
                      providerTokenRef:
                        type: string
              example:
                resourceId: 704
                changes:
                  providerTokenRef: vault:ach:tok_sandbox_bank_45
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - providerTokenRef
              properties:
                providerTokenRef:
                  type: string
              example:
                providerTokenRef: vault:ach:tok_sandbox_bank_45
            example:
              providerTokenRef: vault:ach:tok_sandbox_bank_45
  /v1/external-parties/{partyId}/payment-instruments/{instrumentId}/deactivate:
    post:
      tags:
        - Payment instruments
      operationId: deactivateExternalPartyPaymentInstrument
      summary: Deactivate a payment instrument
      description: "Stops future use and cascades dependent autopay enrollments into review. Idempotent: deactivating an
        inactive instrument is a no-op."
      x-permission: UPDATE_LMS_PAYMENT_INSTRUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 704
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: CUSTOMER_REQUEST
                comment: Account closed at bank.
            example:
              reasonCode: CUSTOMER_REQUEST
              comment: Account closed at bank.
  /v1/external-parties/{partyId}/payment-instruments/{instrumentId}/sensitive:
    get:
      tags:
        - Payment instruments
      operationId: getExternalPartyPaymentInstrumentSensitive
      summary: Retrieve sensitive instrument references
      description: Returns the masked fields plus the vault token and authorization reference. Requires both read permissions;
        every call is audited and the response is never cached.
      x-permission: READ_LMS_PAYMENT_INSTRUMENT & READ_LMS_PAYMENT_INSTRUMENT_SENSITIVE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: instrumentId
          in: path
          required: true
          description: Stable opaque instrument identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - instrumentId
                  - instrumentType
                  - maskedDisplay
                  - railCapabilities
                  - verificationState
                  - accountValidationStatus
                  - status
                  - createdAt
                  - lastModifiedAt
                  - providerTokenRef
                  - authorizationRef
                properties:
                  instrumentId:
                    type: integer
                  instrumentType:
                    type: string
                  maskedDisplay:
                    type: string
                  railCapabilities:
                    type: array
                    items:
                      type: string
                  verificationState:
                    type: string
                  accountValidationStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
                  providerTokenRef:
                    type: string
                  authorizationRef:
                    type: string
              example:
                instrumentId: 704
                instrumentType: ACH_BANK
                maskedDisplay: ••6789
                railCapabilities:
                  - ACH
                verificationState: VERIFIED
                accountValidationStatus: VALIDATED
                status: ACTIVE
                createdAt: 2026-08-11T16:10:00Z
                lastModifiedAt: 2026-08-11T16:12:00Z
                providerTokenRef: vault:ach:tok_sandbox_bank_44
                authorizationRef: evd_BANK_AUTH_11
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/parties:
    get:
      tags:
        - Loan parties
      operationId: listLoanParties
      summary: List loan parties
      description: Lists co-borrower, guarantor, and authorized-party relationships for the loan. Removed parties are excluded
        unless requested by status.
      x-permission: READ_LMS_LOAN_PARTY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Filter by party status; the default excludes REMOVED.
          schema:
            type: string
            enum:
              - PENDING_VERIFICATION
              - ACTIVE
              - REMOVED
        - name: role
          in: query
          required: false
          description: Filter by party role.
          schema:
            type: string
        - name: partyOwnerType
          in: query
          required: false
          description: Filter by owner type.
          schema:
            type: string
            enum:
              - CUSTOMER
              - EXTERNAL_PARTY
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - partyId
                        - loanRef
                        - partyOwnerType
                        - partyOwnerRef
                        - role
                        - authorityScope
                        - status
                        - effectiveFrom
                        - evidenceRef
                        - createdAt
                        - lastModifiedAt
                      properties:
                        partyId:
                          type: integer
                        loanRef:
                          type: string
                        partyOwnerType:
                          type: string
                        partyOwnerRef:
                          type: string
                        role:
                          type: string
                        authorityScope:
                          type: object
                          required:
                            - mayReceiveInformation
                            - mayMakePayments
                            - maySignDocuments
                            - mayApproveActions
                            - mayReceiveNotices
                          properties:
                            mayReceiveInformation:
                              type: boolean
                            mayMakePayments:
                              type: boolean
                            maySignDocuments:
                              type: boolean
                            mayApproveActions:
                              type: boolean
                            mayReceiveNotices:
                              type: boolean
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        effectiveFrom:
                          type: string
                        evidenceRef:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - partyId: 88
                    loanRef: "7204"
                    partyOwnerType: CUSTOMER
                    partyOwnerRef: "412"
                    role: AUTHORIZED_THIRD_PARTY
                    authorityScope:
                      mayReceiveInformation: true
                      mayMakePayments: false
                      maySignDocuments: false
                      mayApproveActions: false
                      mayReceiveNotices: true
                    status: ACTIVE
                    effectiveFrom: 2027-05-01T00:00:00Z
                    evidenceRef: doc_POA_4
                    createdAt: 2027-05-01T16:00:00Z
                    lastModifiedAt: 2027-05-01T16:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Loan parties
      operationId: createLoanParty
      summary: Add a loan party
      description: Creates a role-scoped relationship for a customer or external party with an explicit authority scope.
        Parties start PENDING_VERIFICATION unless created ACTIVE with evidence; an all-false authority scope is valid
        only for INFORMATIONAL_PARTY.
      x-permission: MANAGE_LMS_LOAN_PARTY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 88
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - partyOwnerType
                - partyOwnerRef
                - role
                - authorityScope
                - effectiveFrom
                - evidenceRef
              properties:
                partyOwnerType:
                  type: string
                partyOwnerRef:
                  type: string
                role:
                  type: string
                authorityScope:
                  type: object
                  required:
                    - mayReceiveInformation
                    - mayMakePayments
                    - maySignDocuments
                    - mayApproveActions
                    - mayReceiveNotices
                  properties:
                    mayReceiveInformation:
                      type: boolean
                    mayMakePayments:
                      type: boolean
                    maySignDocuments:
                      type: boolean
                    mayApproveActions:
                      type: boolean
                    mayReceiveNotices:
                      type: boolean
                effectiveFrom:
                  type: string
                evidenceRef:
                  type: string
              example:
                partyOwnerType: CUSTOMER
                partyOwnerRef: "412"
                role: AUTHORIZED_THIRD_PARTY
                authorityScope:
                  mayReceiveInformation: true
                  mayMakePayments: false
                  maySignDocuments: false
                  mayApproveActions: false
                  mayReceiveNotices: true
                effectiveFrom: 2027-05-01T00:00:00Z
                evidenceRef: doc_POA_4
            example:
              partyOwnerType: CUSTOMER
              partyOwnerRef: "412"
              role: AUTHORIZED_THIRD_PARTY
              authorityScope:
                mayReceiveInformation: true
                mayMakePayments: false
                maySignDocuments: false
                mayApproveActions: false
                mayReceiveNotices: true
              effectiveFrom: 2027-05-01T00:00:00Z
              evidenceRef: doc_POA_4
  /v1/loans/{loanId}/parties/{partyId}:
    get:
      tags:
        - Loan parties
      operationId: getLoanParty
      summary: Retrieve a loan party
      description: Returns the relationship, authority scope, status, effective interval, and evidence reference.
      x-permission: READ_LMS_LOAN_PARTY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - partyId
                  - loanRef
                  - partyOwnerType
                  - partyOwnerRef
                  - role
                  - authorityScope
                  - status
                  - effectiveFrom
                  - evidenceRef
                  - createdAt
                  - lastModifiedAt
                properties:
                  partyId:
                    type: integer
                  loanRef:
                    type: string
                  partyOwnerType:
                    type: string
                  partyOwnerRef:
                    type: string
                  role:
                    type: string
                  authorityScope:
                    type: object
                    required:
                      - mayReceiveInformation
                      - mayMakePayments
                      - maySignDocuments
                      - mayApproveActions
                      - mayReceiveNotices
                    properties:
                      mayReceiveInformation:
                        type: boolean
                      mayMakePayments:
                        type: boolean
                      maySignDocuments:
                        type: boolean
                      mayApproveActions:
                        type: boolean
                      mayReceiveNotices:
                        type: boolean
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  effectiveFrom:
                    type: string
                  evidenceRef:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                partyId: 88
                loanRef: "7204"
                partyOwnerType: CUSTOMER
                partyOwnerRef: "412"
                role: AUTHORIZED_THIRD_PARTY
                authorityScope:
                  mayReceiveInformation: true
                  mayMakePayments: false
                  maySignDocuments: false
                  mayApproveActions: false
                  mayReceiveNotices: true
                status: ACTIVE
                effectiveFrom: 2027-05-01T00:00:00Z
                evidenceRef: doc_POA_4
                createdAt: 2027-05-01T16:00:00Z
                lastModifiedAt: 2027-05-01T16:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Loan parties
      operationId: updateLoanParty
      summary: Update a loan party
      description: Updates role, authority scope, status, effective interval, or evidence. The party owner is immutable.
      x-permission: MANAGE_LMS_LOAN_PARTY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - authorityScope
                    properties:
                      authorityScope:
                        type: string
              example:
                resourceId: 88
                changes:
                  authorityScope: updated
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - authorityScope
              properties:
                authorityScope:
                  type: object
                  required:
                    - mayReceiveInformation
                    - mayMakePayments
                    - maySignDocuments
                    - mayApproveActions
                    - mayReceiveNotices
                  properties:
                    mayReceiveInformation:
                      type: boolean
                    mayMakePayments:
                      type: boolean
                    maySignDocuments:
                      type: boolean
                    mayApproveActions:
                      type: boolean
                    mayReceiveNotices:
                      type: boolean
              example:
                authorityScope:
                  mayReceiveInformation: true
                  mayMakePayments: true
                  maySignDocuments: false
                  mayApproveActions: false
                  mayReceiveNotices: true
            example:
              authorityScope:
                mayReceiveInformation: true
                mayMakePayments: true
                maySignDocuments: false
                mayApproveActions: false
                mayReceiveNotices: true
  /v1/loans/{loanId}/parties/{partyId}/remove:
    post:
      tags:
        - Loan parties
      operationId: removeLoanParty
      summary: Remove a loan party
      description: Ends the relationship with a required reason; the historical interval is retained.
      x-permission: MANAGE_LMS_LOAN_PARTY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 88
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: AUTHORITY_REVOKED
                comment: Power of attorney withdrawn.
            example:
              reasonCode: AUTHORITY_REVOKED
              comment: Power of attorney withdrawn.
  /v1/customers/{customerId}/loan-party-links:
    get:
      tags:
        - Loan parties
      operationId: listCustomerLoanPartyLinks
      summary: List a customer’s loan roles
      description: Lists the loans on which this customer holds a party role, excluding removed links by default.
      x-permission: READ_LMS_LOAN_PARTY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Filter by party status.
          schema:
            type: string
        - name: role
          in: query
          required: false
          description: Filter by party role.
          schema:
            type: string
        - name: loanRef
          in: query
          required: false
          description: Filter by loan reference.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - partyId
                        - loanRef
                        - partyOwnerType
                        - partyOwnerRef
                        - role
                        - authorityScope
                        - status
                        - effectiveFrom
                        - evidenceRef
                        - createdAt
                        - lastModifiedAt
                      properties:
                        partyId:
                          type: integer
                        loanRef:
                          type: string
                        partyOwnerType:
                          type: string
                        partyOwnerRef:
                          type: string
                        role:
                          type: string
                        authorityScope:
                          type: object
                          required:
                            - mayReceiveInformation
                            - mayMakePayments
                            - maySignDocuments
                            - mayApproveActions
                            - mayReceiveNotices
                          properties:
                            mayReceiveInformation:
                              type: boolean
                            mayMakePayments:
                              type: boolean
                            maySignDocuments:
                              type: boolean
                            mayApproveActions:
                              type: boolean
                            mayReceiveNotices:
                              type: boolean
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        effectiveFrom:
                          type: string
                        evidenceRef:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - partyId: 88
                    loanRef: "7204"
                    partyOwnerType: CUSTOMER
                    partyOwnerRef: "412"
                    role: AUTHORIZED_THIRD_PARTY
                    authorityScope:
                      mayReceiveInformation: true
                      mayMakePayments: false
                      maySignDocuments: false
                      mayApproveActions: false
                      mayReceiveNotices: true
                    status: ACTIVE
                    effectiveFrom: 2027-05-01T00:00:00Z
                    evidenceRef: doc_POA_4
                    createdAt: 2027-05-01T16:00:00Z
                    lastModifiedAt: 2027-05-01T16:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/external-parties:
    post:
      tags:
        - External parties
      operationId: createExternalParty
      summary: Create an external party
      description: Creates a merchant or other permitted counterparty. Parties start UNVERIFIED and inactive; activation
        requires VERIFIED. Tax identifiers are vault references — raw values are rejected.
      x-permission: MANAGE_LMS_EXTERNAL_PARTY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 51
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - partyType
                - displayName
                - legalName
                - externalReference
              properties:
                partyType:
                  type: string
                displayName:
                  type: string
                legalName:
                  type: string
                externalReference:
                  type: string
              example:
                partyType: MERCHANT
                displayName: Juniper Home Market
                legalName: Juniper Home Market LLC
                externalReference: merchant-2048
            example:
              partyType: MERCHANT
              displayName: Juniper Home Market
              legalName: Juniper Home Market LLC
              externalReference: merchant-2048
    get:
      tags:
        - External parties
      operationId: listExternalParties
      summary: List external parties
      description: Lists counterparties by type, verification state, activation, and case-insensitive name search.
      x-permission: READ_LMS_EXTERNAL_PARTY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: active
          in: query
          required: false
          description: Filter by activation.
          schema:
            type: boolean
        - name: partyType
          in: query
          required: false
          description: Filter by party type.
          schema:
            type: string
            enum:
              - MERCHANT
              - VENDOR
              - DEALER
              - SCHOOL
              - HEALTHCARE_PROVIDER
              - EMPLOYER
              - INVESTOR
              - OTHER
        - name: verificationState
          in: query
          required: false
          description: Filter by verification state.
          schema:
            type: string
            enum:
              - UNVERIFIED
              - VERIFIED
              - FAILED
              - UNDER_REVIEW
        - name: search
          in: query
          required: false
          description: Case-insensitive substring match on display name.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - partyId
                        - partyType
                        - displayName
                        - legalName
                        - externalReference
                        - active
                        - verificationState
                        - createdAt
                        - lastModifiedAt
                      properties:
                        partyId:
                          type: integer
                        partyType:
                          type: string
                        displayName:
                          type: string
                        legalName:
                          type: string
                        externalReference:
                          type: string
                        active:
                          type: boolean
                        verificationState:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                items:
                  - partyId: 51
                    partyType: MERCHANT
                    displayName: Juniper Home Market
                    legalName: Juniper Home Market LLC
                    externalReference: merchant-2048
                    active: true
                    verificationState: VERIFIED
                    createdAt: 2026-08-01T12:00:00Z
                    lastModifiedAt: 2026-09-01T12:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/external-parties/{partyId}:
    get:
      tags:
        - External parties
      operationId: getExternalParty
      summary: Retrieve an external party
      description: Returns the party detail, including the vaulted tax-identifier reference and metadata that list reads omit.
      x-permission: READ_LMS_EXTERNAL_PARTY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - partyId
                  - partyType
                  - displayName
                  - legalName
                  - externalReference
                  - active
                  - verificationState
                  - createdAt
                  - lastModifiedAt
                  - taxBusinessIdentifierRef
                  - metadata
                properties:
                  partyId:
                    type: integer
                  partyType:
                    type: string
                  displayName:
                    type: string
                  legalName:
                    type: string
                  externalReference:
                    type: string
                  active:
                    type: boolean
                  verificationState:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
                  taxBusinessIdentifierRef:
                    type: string
                  metadata:
                    type: object
                    required:
                      - segment
                    properties:
                      segment:
                        type: string
              example:
                partyId: 51
                partyType: MERCHANT
                displayName: Juniper Home Market
                legalName: Juniper Home Market LLC
                externalReference: merchant-2048
                active: true
                verificationState: VERIFIED
                createdAt: 2026-08-01T12:00:00Z
                lastModifiedAt: 2026-09-01T12:00:00Z
                taxBusinessIdentifierRef: vault:tax:tok_juniper_1
                metadata:
                  segment: home-improvement
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - External parties
      operationId: updateExternalParty
      summary: Update an external party
      description: Merge-updates the party. Activation and verification changes require an audit comment; moving away from
        VERIFIED automatically deactivates the party.
      x-permission: MANAGE_LMS_EXTERNAL_PARTY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: partyId
          in: path
          required: true
          description: Stable opaque party identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - active
                      - verificationState
                    properties:
                      active:
                        type: boolean
                      verificationState:
                        type: string
              example:
                resourceId: 51
                changes:
                  active: true
                  verificationState: VERIFIED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - active
                - verificationState
                - comment
              properties:
                active:
                  type: boolean
                verificationState:
                  type: string
                comment:
                  type: string
              example:
                active: true
                verificationState: VERIFIED
                comment: KYB review completed.
            example:
              active: true
              verificationState: VERIFIED
              comment: KYB review completed.
  /v1/portfolio/search:
    get:
      tags:
        - Search
      operationId: searchPortfolio
      summary: Search customers and loans
      description: "Permission-aware exact and prefix search: name token-prefix, exact current email, canonical phone, and
        exact loan account number. Results are safe summaries; the query and matched contact values are never echoed,
        and the response is never cached."
      x-permission: READ_LMS_CUSTOMER | READ_LMS_LOAN_SUMMARY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: q
          in: query
          required: true
          description: Search text, 2–320 characters after trimming.
          schema:
            type: string
            minLength: 2
            maxLength: 320
        - name: type
          in: query
          required: false
          description: Restrict to one result type; omit for both.
          schema:
            type: string
            enum:
              - customer
              - loan
        - name: limit
          in: query
          required: false
          description: Maximum results to return.
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 25
        - name: cursor
          in: query
          required: false
          description: Opaque cursor bound to the same query, type set, and caller scope.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                  - nextCursor
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - resultType
                        - customerId
                        - displayName
                        - customerType
                        - status
                      properties:
                        resultType:
                          type: string
                        customerId:
                          type: string
                          description: Stable opaque customer identifier.
                        displayName:
                          type: string
                        customerType:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                  nextCursor:
                    type: string
              example:
                items:
                  - resultType: CUSTOMER
                    customerId: "412"
                    displayName: Maya Chen
                    customerType: INDIVIDUAL
                    status: ACTIVE
                  - resultType: LOAN
                    loanId: "7204"
                    customerId: "412"
                    displayName: Maya Chen
                    loanAccountNumber: "000007204"
                    loanProductId: 3
                    loanProductName: Harbor 18-month personal loan
                    status: ACTIVE
                nextCursor: null
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/restrictions:
    post:
      tags:
        - Restrictions
      operationId: applyRestriction
      summary: Apply a restriction
      description: Applies a typed hold at customer scope, or loan scope when loanRef is supplied. The server derives the
        effective time; applying an already-active restriction of the same type and scope is idempotent. AUTOPAY_HOLD
        and COLLECTIONS_HOLD pause affected autopay enrollments in the same transaction.
      x-permission: APPLY_LMS_RESTRICTION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 41
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - restrictionType
                - loanRef
                - source
              properties:
                restrictionType:
                  type: string
                loanRef:
                  type: string
                source:
                  type: string
                  description: System or actor that originated the record.
              example:
                restrictionType: PAYMENT_HOLD
                loanRef: "7204"
                source: bankruptcy-notice-91
            example:
              restrictionType: PAYMENT_HOLD
              loanRef: "7204"
              source: bankruptcy-notice-91
    get:
      tags:
        - Restrictions
      operationId: listCustomerRestrictions
      summary: List customer restrictions
      description: Returns the customer’s restrictions, newest first, including cleared rows with their clearedAt time.
      x-permission: READ_LMS_CUSTOMER
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - restrictionId
                        - restrictionType
                        - loanRef
                        - active
                        - source
                        - effectiveAt
                      properties:
                        restrictionId:
                          type: integer
                        restrictionType:
                          type: string
                        loanRef:
                          type: string
                        active:
                          type: boolean
                        source:
                          type: string
                          description: System or actor that originated the record.
                        effectiveAt:
                          type: string
                          format: date-time
              example:
                items:
                  - restrictionId: 41
                    restrictionType: PAYMENT_HOLD
                    loanRef: "7204"
                    active: true
                    source: case:case_HBR_BANKRUPTCY_3
                    effectiveAt: 2027-06-03T14:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/restrictions/{restrictionId}/clear:
    post:
      tags:
        - Restrictions
      operationId: clearRestriction
      summary: Clear a restriction
      description: Clears the restriction with no request body; the server records who cleared it and when. The applied
        interval remains in history and governance records.
      x-permission: APPLY_LMS_RESTRICTION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: restrictionId
          in: path
          required: true
          description: Stable opaque restriction identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 41
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/loans/{loanId}/governance-records:
    get:
      tags:
        - Servicing actions
      operationId: listLoanGovernanceRecords
      summary: List loan governance records
      description: "Returns the governance ledger for governed commands executed against the loan: who acted, under which case
        or system context, through which route, newest first."
      x-permission: READ_LMS_GOVERNANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - governanceId
                        - occurredAt
                        - contextType
                        - contextRef
                        - permissionCode
                        - route
                        - actorClass
                        - correlationId
                      properties:
                        governanceId:
                          type: integer
                        occurredAt:
                          type: string
                          format: date-time
                        contextType:
                          type: string
                        contextRef:
                          type: string
                        permissionCode:
                          type: string
                        route:
                          type: string
                        actorClass:
                          type: string
                        correlationId:
                          type: string
              example:
                items:
                  - governanceId: 902
                    occurredAt: 2027-08-20T17:14:09Z
                    contextType: CASE
                    contextRef: case_CEDAR_HARDSHIP_4
                    permissionCode: WAIVEINTERESTPORTION_LOAN
                    route: POST /v1/loans/7204/transactions?command=waiveinterest
                    actorClass: HUMAN
                    correlationId: corr_01JZ7M5KX2
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/governance-records:
    get:
      tags:
        - Servicing actions
      operationId: listCustomerGovernanceRecords
      summary: List customer governance records
      description: Returns the governance ledger for governed commands executed against the customer, newest first.
      x-permission: READ_LMS_GOVERNANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - governanceId
                        - occurredAt
                        - contextType
                        - contextRef
                        - permissionCode
                        - route
                        - actorClass
                        - correlationId
                      properties:
                        governanceId:
                          type: integer
                        occurredAt:
                          type: string
                          format: date-time
                        contextType:
                          type: string
                        contextRef:
                          type: string
                        permissionCode:
                          type: string
                        route:
                          type: string
                        actorClass:
                          type: string
                        correlationId:
                          type: string
              example:
                items:
                  - governanceId: 903
                    occurredAt: 2027-08-20T17:14:09Z
                    contextType: CASE
                    contextRef: case_CEDAR_HARDSHIP_4
                    permissionCode: APPLY_LMS_RESTRICTION
                    route: POST /v1/customers/412/restrictions
                    actorClass: HUMAN
                    correlationId: corr_01JZ7M5KX2
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/payments:
    post:
      tags:
        - Payments
      operationId: createPayment
      summary: Create a payment
      description: Creates a payment intent against a verified, borrower-owned instrument and submits it to the selected rail.
        The amount plus other in-flight intents may not exceed the loan’s total outstanding, and PAYMENT_HOLD
        restrictions block creation. Reusing an Idempotency-Key with a different payload fails with a fingerprint
        mismatch.
      x-permission: CREATE_LMS_PAYMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - paymentId
                  - loanRef
                  - status
                  - attemptNumber
                properties:
                  paymentId:
                    type: integer
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptNumber:
                    type: integer
              example:
                paymentId: 9011
                loanRef: "7204"
                status: CREATED
                attemptNumber: 1
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - instrumentId
                - amount
                - currency
                - rail
                - effectiveDate
                - source
              properties:
                instrumentId:
                  type: integer
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                rail:
                  type: string
                effectiveDate:
                  type: string
                  format: date
                  description: Business-effective date in ISO 8601 format.
                source:
                  type: string
                  description: System or actor that originated the record.
              example:
                instrumentId: 704
                amount: "517.14"
                currency: USD
                rail: ACH
                effectiveDate: 2026-09-12
                source: BORROWER
            example:
              instrumentId: 704
              amount: "517.14"
              currency: USD
              rail: ACH
              effectiveDate: 2026-09-12
              source: BORROWER
    get:
      tags:
        - Payments
      operationId: listLoanPayments
      summary: List loan payments
      description: Lists payment intents for the loan with status, rail, source, and return metadata when present.
      x-permission: READ_LMS_PAYMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: status
          in: query
          required: false
          description: Repeatable status filter.
          schema:
            type: string
            enum:
              - CREATED
              - VALIDATED
              - SUBMITTED
              - PROCESSING
              - SETTLED_PENDING_POST
              - POSTED
              - RETURNED
              - FAILED
              - CANCELLED
              - RECORDED_EXTERNAL
        - name: source
          in: query
          required: false
          description: Filter by originating source.
          schema:
            type: string
            enum:
              - BORROWER
              - STAFF
              - AUTOPAY
              - SERVICING
              - EXTERNAL
              - IMPORT
        - name: rail
          in: query
          required: false
          description: Filter by rail.
          schema:
            type: string
            enum:
              - ACH
              - CARD
              - EXTERNAL
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - paymentId
                        - loanRef
                        - status
                        - attemptNumber
                        - amount
                        - currency
                        - rail
                        - effectiveDate
                        - source
                        - createdAt
                        - postedTransactionRef
                      properties:
                        paymentId:
                          type: integer
                        loanRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        attemptNumber:
                          type: integer
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        rail:
                          type: string
                        effectiveDate:
                          type: string
                          format: date
                          description: Business-effective date in ISO 8601 format.
                        source:
                          type: string
                          description: System or actor that originated the record.
                        createdAt:
                          type: string
                          format: date-time
                        postedTransactionRef:
                          type: string
              example:
                items:
                  - paymentId: 9011
                    loanRef: "7204"
                    status: POSTED
                    attemptNumber: 1
                    amount: "517.14"
                    currency: USD
                    rail: ACH
                    effectiveDate: 2026-09-12
                    source: BORROWER
                    createdAt: 2026-09-11T17:03:00Z
                    postedTransactionRef: "30411"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/payments/record-external:
    post:
      tags:
        - Payments
      operationId: recordExternalPayment
      summary: Record an external payment
      description: Records money received outside LendEasy — lockbox, wire, import — without calling a payment rail.
        STAFF-sourced records require an evidence reference; a rationale is always required. Set postToFineract to false
        to record without posting, leaving the intent in RECORDED_EXTERNAL for reconciliation.
      x-permission: RECORD_LMS_EXTERNAL_PAYMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - paymentId
                  - loanRef
                  - status
                  - attemptNumber
                properties:
                  paymentId:
                    type: integer
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptNumber:
                    type: integer
              example:
                paymentId: 9012
                loanRef: "7204"
                status: RECORDED_EXTERNAL
                attemptNumber: 1
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - currency
                - effectiveDate
                - externalRecordRef
                - source
                - evidenceRef
                - rationale
              properties:
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                effectiveDate:
                  type: string
                  format: date
                  description: Business-effective date in ISO 8601 format.
                externalRecordRef:
                  type: string
                source:
                  type: string
                  description: System or actor that originated the record.
                evidenceRef:
                  type: string
                rationale:
                  type: string
              example:
                amount: "260.00"
                currency: USD
                effectiveDate: 2027-05-08
                externalRecordRef: lockbox-20270508-881
                source: STAFF
                evidenceRef: evd_LOCKBOX_8
                rationale: Lockbox batch 881 posting.
            example:
              amount: "260.00"
              currency: USD
              effectiveDate: 2027-05-08
              externalRecordRef: lockbox-20270508-881
              source: STAFF
              evidenceRef: evd_LOCKBOX_8
              rationale: Lockbox batch 881 posting.
  /v1/loans/{loanId}/payments/{paymentId}:
    get:
      tags:
        - Payments
      operationId: getPayment
      summary: Retrieve a payment
      description: Returns the payment intent with its state timeline. Returned payments carry the return code, returned
        amount, and any scheduled retry; retries are new intents linked through retryRootPaymentId.
      x-permission: READ_LMS_PAYMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: paymentId
          in: path
          required: true
          description: Stable opaque payment identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - paymentId
                  - loanRef
                  - status
                  - attemptNumber
                  - amount
                  - currency
                  - rail
                  - effectiveDate
                  - source
                  - createdAt
                  - postedTransactionRef
                  - metadata
                  - timeline
                properties:
                  paymentId:
                    type: integer
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  attemptNumber:
                    type: integer
                  amount:
                    type: string
                    description: Decimal monetary amount encoded as a string.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  rail:
                    type: string
                  effectiveDate:
                    type: string
                    format: date
                    description: Business-effective date in ISO 8601 format.
                  source:
                    type: string
                    description: System or actor that originated the record.
                  createdAt:
                    type: string
                    format: date-time
                  postedTransactionRef:
                    type: string
                  metadata:
                    type: object
                    required:
                      - channel
                    properties:
                      channel:
                        type: string
                  timeline:
                    type: array
                    items:
                      type: object
                      required:
                        - occurredAt
                        - source
                        - state
                      properties:
                        occurredAt:
                          type: string
                          format: date-time
                        source:
                          type: string
                          description: System or actor that originated the record.
                        state:
                          type: string
              example:
                paymentId: 9011
                loanRef: "7204"
                status: POSTED
                attemptNumber: 1
                amount: "517.14"
                currency: USD
                rail: ACH
                effectiveDate: 2026-09-12
                source: BORROWER
                createdAt: 2026-09-11T17:03:00Z
                postedTransactionRef: "30411"
                metadata:
                  channel: borrower_portal
                timeline:
                  - occurredAt: 2026-09-11T17:03:00Z
                    source: LMS
                    state: SUBMITTED
                  - occurredAt: 2026-09-15T14:22:08Z
                    source: LMS
                    state: POSTED
                    postedTransactionRef: "30411"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/payments/{paymentId}/receipt:
    get:
      tags:
        - Payments
      operationId: getPaymentReceipt
      summary: Download a payment receipt
      description: Returns the receipt PDF for a POSTED payment as an attachment. Requesting a receipt for any other status
        fails validation; a later return does not alter an issued receipt.
      x-permission: READ_LMS_PAYMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: paymentId
          in: path
          required: true
          description: Stable opaque payment identifier.
          schema:
            type: string
      responses:
        "200":
          description: Receipt PDF attachment.
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/autopay:
    post:
      tags:
        - Autopay
      operationId: enrollAutopay
      summary: Enroll in autopay
      description: Creates the loan’s single current enrollment from a verified instrument, timing policy, and amount policy.
        A Regulation E authorization reference is required to activate. FULL_DUE enrollments must leave enough statement
        lead time for the ten-day advance notice.
      x-permission: ENROLL_LMS_AUTOPAY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 31
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - instrumentId
                - authorizationRef
                - timingPolicy
                - amountPolicy
              properties:
                instrumentId:
                  type: integer
                authorizationRef:
                  type: string
                timingPolicy:
                  type: object
                  required:
                    - initiateDaysBeforeDue
                    - businessDayConvention
                  properties:
                    initiateDaysBeforeDue:
                      type: integer
                    businessDayConvention:
                      type: string
                amountPolicy:
                  type: object
                  required:
                    - type
                  properties:
                    type:
                      type: string
              example:
                instrumentId: 704
                authorizationRef: evd_JUN_AP_73
                timingPolicy:
                  initiateDaysBeforeDue: 0
                  businessDayConvention: FOLLOWING
                amountPolicy:
                  type: FULL_DUE
            example:
              instrumentId: 704
              authorizationRef: evd_JUN_AP_73
              timingPolicy:
                initiateDaysBeforeDue: 0
                businessDayConvention: FOLLOWING
              amountPolicy:
                type: FULL_DUE
    get:
      tags:
        - Autopay
      operationId: getAutopayEnrollment
      summary: Retrieve autopay enrollment
      description: "Returns the current enrollment: status, masked instrument, policies, authorization reference, and failure
        count. Loans with no enrollment return 404."
      x-permission: READ_LMS_AUTOPAY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - loanRef
                  - status
                  - instrument
                  - timingPolicy
                  - amountPolicy
                  - authorizationRef
                  - consecutiveFailureCount
                  - effectiveDate
                properties:
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  instrument:
                    type: object
                    required:
                      - instrumentId
                      - maskedDisplay
                    properties:
                      instrumentId:
                        type: integer
                      maskedDisplay:
                        type: string
                  timingPolicy:
                    type: object
                    required:
                      - initiateDaysBeforeDue
                      - businessDayConvention
                      - onScheduleChange
                    properties:
                      initiateDaysBeforeDue:
                        type: integer
                      businessDayConvention:
                        type: string
                      onScheduleChange:
                        type: string
                  amountPolicy:
                    type: object
                    required:
                      - type
                    properties:
                      type:
                        type: string
                  authorizationRef:
                    type: string
                  consecutiveFailureCount:
                    type: integer
                  effectiveDate:
                    type: string
                    format: date
                    description: Business-effective date in ISO 8601 format.
              example:
                loanRef: "7204"
                status: ACTIVE
                instrument:
                  instrumentId: 704
                  maskedDisplay: ••6789
                timingPolicy:
                  initiateDaysBeforeDue: 0
                  businessDayConvention: FOLLOWING
                  onScheduleChange: FOLLOW_NEW_SCHEDULE
                amountPolicy:
                  type: FULL_DUE
                authorizationRef: evd_JUN_AP_73
                consecutiveFailureCount: 0
                effectiveDate: 2026-08-21
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/autopay/pause:
    post:
      tags:
        - Autopay
      operationId: pauseAutopay
      summary: Pause autopay
      description: Pauses an ACTIVE enrollment. Requires a reason code from the closed catalog; a request that would repeat
        the current state is a successful no-op.
      x-permission: PAUSE_LMS_AUTOPAY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 31
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: BORROWER_REQUEST
                comment: Requested via secure message.
            example:
              reasonCode: BORROWER_REQUEST
              comment: Requested via secure message.
  /v1/loans/{loanId}/autopay/resume:
    post:
      tags:
        - Autopay
      operationId: resumeAutopay
      summary: Resume autopay
      description: Resumes a PAUSED or REVIEW_REQUIRED enrollment, clearing the review reason and failure count. Requires a
        reason code from the closed catalog; a request that would repeat the current state is a successful no-op.
      x-permission: RESUME_LMS_AUTOPAY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 31
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: BORROWER_REQUEST
                comment: Borrower reauthorized after account change.
            example:
              reasonCode: BORROWER_REQUEST
              comment: Borrower reauthorized after account change.
  /v1/loans/{loanId}/autopay/cancel:
    post:
      tags:
        - Autopay
      operationId: cancelAutopay
      summary: Cancel autopay
      description: Cancels the enrollment from any state and cancels its pending unsubmitted payment intents; Regulation E
        treats this as revocation. Requires a reason code from the closed catalog; a request that would repeat the
        current state is a successful no-op.
      x-permission: CANCEL_LMS_AUTOPAY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 31
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: BORROWER_REQUEST
                comment: Requested via secure message.
            example:
              reasonCode: BORROWER_REQUEST
              comment: Requested via secure message.
  /v1/autopay/failure-policies:
    get:
      tags:
        - Autopay
      operationId: listAutopayFailurePolicies
      summary: List autopay failure policies
      description: Returns the tenant’s per-rail failure policy, including retry rules and per-return-code overrides. Unknown
        return codes always fail closed into review.
      x-permission: READ_LMS_AUTOPAY_FAILURE_POLICY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - rails
                properties:
                  rails:
                    type: array
                    items:
                      type: object
                      required:
                        - rail
                        - automaticRetry
                        - retryAfterBusinessDays
                        - maxRetryAttempts
                        - maxConsecutiveFailedCycles
                        - runNextScheduledCycle
                        - exhaustionAction
                        - returnCodes
                      properties:
                        rail:
                          type: string
                        automaticRetry:
                          type: boolean
                        retryAfterBusinessDays:
                          type: integer
                        maxRetryAttempts:
                          type: integer
                        maxConsecutiveFailedCycles:
                          type: integer
                        runNextScheduledCycle:
                          type: boolean
                        exhaustionAction:
                          type: string
                        returnCodes:
                          type: array
                          items:
                            type: object
                            required:
                              - returnCode
                              - retryAllowed
                              - instrumentAction
                              - autopayAction
                              - caseAction
                              - recommendedAction
                              - treatAsUnauthorized
                            properties:
                              returnCode:
                                type: string
                              retryAllowed:
                                type: boolean
                              instrumentAction:
                                type: string
                              autopayAction:
                                type: string
                              caseAction:
                                type: string
                              recommendedAction:
                                type: string
                              treatAsUnauthorized:
                                type: boolean
              example:
                rails:
                  - rail: ACH
                    automaticRetry: true
                    retryAfterBusinessDays: 2
                    maxRetryAttempts: 2
                    maxConsecutiveFailedCycles: 3
                    runNextScheduledCycle: true
                    exhaustionAction: REVIEW_REQUIRED
                    returnCodes:
                      - returnCode: R01
                        retryAllowed: true
                        instrumentAction: KEEP
                        autopayAction: CONTINUE
                        caseAction: NONE
                        recommendedAction: NONE
                        treatAsUnauthorized: false
                      - returnCode: R10
                        retryAllowed: false
                        instrumentAction: INVALIDATE
                        autopayAction: CANCELLED
                        caseAction: OPEN_PAYMENT_FAILURE
                        recommendedAction: CANCEL_AUTOPAY
                        treatAsUnauthorized: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/autopay/failure-policies/{rail}:
    put:
      tags:
        - Autopay
      operationId: configureAutopayFailurePolicy
      summary: Configure an autopay failure policy
      description: Replaces the full policy for one rail — base retry rules and the complete return-code list. The rail path
        segment is ACH or CARD.
      x-permission: CONFIGURE_LMS_AUTOPAY_FAILURE_POLICY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: rail
          in: path
          required: true
          description: Stable opaque rail identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 2
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - automaticRetry
                - retryAfterBusinessDays
                - maxRetryAttempts
                - maxConsecutiveFailedCycles
                - runNextScheduledCycle
                - exhaustionAction
                - returnCodes
              properties:
                automaticRetry:
                  type: boolean
                retryAfterBusinessDays:
                  type: integer
                maxRetryAttempts:
                  type: integer
                maxConsecutiveFailedCycles:
                  type: integer
                runNextScheduledCycle:
                  type: boolean
                exhaustionAction:
                  type: string
                returnCodes:
                  type: array
                  items:
                    type: object
                    required:
                      - returnCode
                      - retryAllowed
                      - instrumentAction
                      - autopayAction
                      - caseAction
                      - recommendedAction
                      - treatAsUnauthorized
                    properties:
                      returnCode:
                        type: string
                      retryAllowed:
                        type: boolean
                      instrumentAction:
                        type: string
                      autopayAction:
                        type: string
                      caseAction:
                        type: string
                      recommendedAction:
                        type: string
                      treatAsUnauthorized:
                        type: boolean
              example:
                automaticRetry: true
                retryAfterBusinessDays: 2
                maxRetryAttempts: 2
                maxConsecutiveFailedCycles: 3
                runNextScheduledCycle: true
                exhaustionAction: REVIEW_REQUIRED
                returnCodes:
                  - returnCode: R01
                    retryAllowed: true
                    instrumentAction: KEEP
                    autopayAction: CONTINUE
                    caseAction: NONE
                    recommendedAction: NONE
                    treatAsUnauthorized: false
            example:
              automaticRetry: true
              retryAfterBusinessDays: 2
              maxRetryAttempts: 2
              maxConsecutiveFailedCycles: 3
              runNextScheduledCycle: true
              exhaustionAction: REVIEW_REQUIRED
              returnCodes:
                - returnCode: R01
                  retryAllowed: true
                  instrumentAction: KEEP
                  autopayAction: CONTINUE
                  caseAction: NONE
                  recommendedAction: NONE
                  treatAsUnauthorized: false
  /v1/loans/{loanId}/fundings:
    post:
      tags:
        - Funding
      operationId: createFunding
      summary: Create a funding
      description: Creates an outbound payout — a DISBURSEMENT for an approved loan or a REFUND — to a verified borrower or
        external-party instrument. Every funding starts in APPROVAL_REQUIRED; a different user must approve before
        submission. DISBURSEMENT_HOLD restrictions block creation.
      x-permission: CREATE_LMS_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - fundingId
                  - loanRef
                  - status
                properties:
                  fundingId:
                    type: integer
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
              example:
                fundingId: 5107
                loanRef: "7204"
                status: APPROVAL_REQUIRED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - currency
                - fundingType
                - recipientType
                - recipientRef
                - instrumentId
                - rail
                - reason
              properties:
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                fundingType:
                  type: string
                recipientType:
                  type: string
                recipientRef:
                  type: string
                instrumentId:
                  type: integer
                rail:
                  type: string
                reason:
                  type: string
              example:
                amount: "8400.00"
                currency: USD
                fundingType: DISBURSEMENT
                recipientType: BORROWER
                recipientRef: "412"
                instrumentId: 705
                rail: ACH
                reason: Initial disbursement for approved loan.
            example:
              amount: "8400.00"
              currency: USD
              fundingType: DISBURSEMENT
              recipientType: BORROWER
              recipientRef: "412"
              instrumentId: 705
              rail: ACH
              reason: Initial disbursement for approved loan.
    get:
      tags:
        - Funding
      operationId: listLoanFundings
      summary: List loan fundings
      description: Lists the loan’s fundings, newest first.
      x-permission: READ_LMS_FUNDING
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - fundingId
                        - loanRef
                        - fundingType
                        - recipientType
                        - recipientRef
                        - status
                        - amount
                        - currency
                        - rail
                        - postedTransactionRef
                        - createdAt
                      properties:
                        fundingId:
                          type: integer
                        loanRef:
                          type: string
                        fundingType:
                          type: string
                        recipientType:
                          type: string
                        recipientRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        rail:
                          type: string
                        postedTransactionRef:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
              example:
                items:
                  - fundingId: 5107
                    loanRef: "7204"
                    fundingType: DISBURSEMENT
                    recipientType: BORROWER
                    recipientRef: "412"
                    status: POSTED
                    amount: "8400.00"
                    currency: USD
                    rail: ACH
                    postedTransactionRef: "30119"
                    createdAt: 2026-08-11T18:20:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/fundings/record-external:
    post:
      tags:
        - Funding
      operationId: recordExternalFunding
      summary: Record external funding
      description: Records a payout made outside LendEasy — for example a treasury wire — with an external record reference.
        No instrument or rail is involved and no money moves; the record enters reconciliation as RECORDED_EXTERNAL.
      x-permission: CREATE_LMS_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - fundingId
                  - loanRef
                  - status
                properties:
                  fundingId:
                    type: integer
                  loanRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
              example:
                fundingId: 5108
                loanRef: "7204"
                status: RECORDED_EXTERNAL
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - currency
                - fundingType
                - recipientType
                - recipientRef
                - externalRecordRef
                - reason
              properties:
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                fundingType:
                  type: string
                recipientType:
                  type: string
                recipientRef:
                  type: string
                externalRecordRef:
                  type: string
                reason:
                  type: string
              example:
                amount: "8400.00"
                currency: USD
                fundingType: DISBURSEMENT
                recipientType: BORROWER
                recipientRef: "412"
                externalRecordRef: wire-20260812-881
                reason: Disbursed by treasury wire.
            example:
              amount: "8400.00"
              currency: USD
              fundingType: DISBURSEMENT
              recipientType: BORROWER
              recipientRef: "412"
              externalRecordRef: wire-20260812-881
              reason: Disbursed by treasury wire.
  /v1/loans/{loanId}/fundings/{fundingId}:
    get:
      tags:
        - Funding
      operationId: getFunding
      summary: Retrieve a funding
      description: Returns the funding with its status, recipient, rail, posted transaction reference, and failure reason when
        present.
      x-permission: READ_LMS_FUNDING
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: fundingId
          in: path
          required: true
          description: Stable opaque funding identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - fundingId
                  - loanRef
                  - fundingType
                  - recipientType
                  - recipientRef
                  - status
                  - amount
                  - currency
                  - rail
                  - postedTransactionRef
                  - createdAt
                properties:
                  fundingId:
                    type: integer
                  loanRef:
                    type: string
                  fundingType:
                    type: string
                  recipientType:
                    type: string
                  recipientRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  amount:
                    type: string
                    description: Decimal monetary amount encoded as a string.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  rail:
                    type: string
                  postedTransactionRef:
                    type: string
                  createdAt:
                    type: string
                    format: date-time
              example:
                fundingId: 5107
                loanRef: "7204"
                fundingType: DISBURSEMENT
                recipientType: BORROWER
                recipientRef: "412"
                status: POSTED
                amount: "8400.00"
                currency: USD
                rail: ACH
                postedTransactionRef: "30119"
                createdAt: 2026-08-11T18:20:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/fundings/{fundingId}/approve:
    post:
      tags:
        - Funding
      operationId: approveFunding
      summary: Approve a funding
      description: Approves a funding in APPROVAL_REQUIRED. The creator can never approve their own funding; approval releases
        it for value-dated submission to the rail.
      x-permission: APPROVE_LMS_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
            - actions:approve
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: fundingId
          in: path
          required: true
          description: Stable opaque funding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 5107
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/loans/{loanId}/fundings/{fundingId}/reject:
    post:
      tags:
        - Funding
      operationId: rejectFunding
      summary: Reject a funding
      description: Rejects a funding awaiting approval with a required reason code.
      x-permission: APPROVE_LMS_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
            - actions:approve
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: fundingId
          in: path
          required: true
          description: Stable opaque funding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 5107
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: AMOUNT_INCORRECT
            example:
              reasonCode: AMOUNT_INCORRECT
  /v1/loans/{loanId}/fundings/{fundingId}/cancel:
    post:
      tags:
        - Funding
      operationId: cancelFunding
      summary: Cancel a funding
      description: Cancels a funding before money movement — while CREATED, VALIDATED, APPROVAL_REQUIRED, or APPROVED. After
        submission the funding can no longer be cancelled; cancelling an already-cancelled funding is a no-op.
      x-permission: CREATE_LMS_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: fundingId
          in: path
          required: true
          description: Stable opaque funding identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 5107
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: OPERATOR_REQUEST
                comment: Recreating with corrected amount.
            example:
              reasonCode: OPERATOR_REQUEST
              comment: Recreating with corrected amount.
  /v1/recon-exceptions:
    get:
      tags:
        - Reconciliation
      operationId: listReconExceptions
      summary: List reconciliation exceptions
      description: Lists differences between provider events, payment and funding intents, and the ledger. Exception types
        include stuck-before-submit, settled-not-posted, recorded-not-posted, return-needs-review, duplicate-reference,
        and record-mismatch checks.
      x-permission: READ_LMS_RECONCILIATION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: status
          in: query
          required: false
          description: Filter by exception status.
          schema:
            type: string
            enum:
              - open
              - in_review
              - resolved
              - exported
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - exceptionId
                        - exceptionType
                        - targetType
                        - targetRef
                        - status
                        - detail
                        - createdAt
                        - lastSeenAt
                      properties:
                        exceptionId:
                          type: integer
                        exceptionType:
                          type: string
                        targetType:
                          type: string
                        targetRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        detail:
                          type: object
                          required:
                            - providerRef
                          properties:
                            providerRef:
                              type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastSeenAt:
                          type: string
                          format: date-time
              example:
                items:
                  - exceptionId: 3301
                    exceptionType: SETTLED_NOT_POSTED
                    targetType: PAYMENT_INTENT
                    targetRef: "9011"
                    status: open
                    detail:
                      providerRef: ach-settle-88
                    createdAt: 2026-09-15T14:30:00Z
                    lastSeenAt: 2026-09-15T18:30:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/recon-exceptions/{exceptionId}:
    get:
      tags:
        - Reconciliation
      operationId: getReconException
      summary: Retrieve a reconciliation exception
      description: Returns the exception with its target reference, structured detail, and resolution note when resolved.
      x-permission: READ_LMS_RECONCILIATION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: exceptionId
          in: path
          required: true
          description: Stable opaque exception identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - exceptionId
                  - exceptionType
                  - targetType
                  - targetRef
                  - status
                  - detail
                  - createdAt
                  - lastSeenAt
                properties:
                  exceptionId:
                    type: integer
                  exceptionType:
                    type: string
                  targetType:
                    type: string
                  targetRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  detail:
                    type: object
                    required:
                      - providerRef
                    properties:
                      providerRef:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastSeenAt:
                    type: string
                    format: date-time
              example:
                exceptionId: 3301
                exceptionType: SETTLED_NOT_POSTED
                targetType: PAYMENT_INTENT
                targetRef: "9011"
                status: open
                detail:
                  providerRef: ach-settle-88
                createdAt: 2026-09-15T14:30:00Z
                lastSeenAt: 2026-09-15T18:30:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/recon-exceptions/{exceptionId}/status:
    post:
      tags:
        - Reconciliation
      operationId: updateReconExceptionStatus
      summary: Update exception status
      description: Moves the exception between open, in_review, resolved, and exported. Resolving requires a note explaining
        the outcome; the route records workflow state and never performs financial repair itself.
      x-permission: RESOLVE_LMS_RECON_EXCEPTION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: exceptionId
          in: path
          required: true
          description: Stable opaque exception identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 3301
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - status
                - note
              properties:
                status:
                  type: string
                  description: Current normalized lifecycle state.
                note:
                  type: string
              example:
                status: resolved
                note: Ledger post repaired from provider settlement evidence.
            example:
              status: resolved
              note: Ledger post repaired from provider settlement evidence.
  /v1/recon-exceptions/export:
    get:
      tags:
        - Reconciliation
      operationId: exportReconExceptions
      summary: Export reconciliation exceptions
      description: Downloads unresolved exceptions as a CSV attachment and marks exported open rows as exported.
      x-permission: READ_LMS_RECONCILIATION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: CSV attachment of unresolved exceptions.
          content:
            text/csv:
              schema:
                type: string
                format: binary
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/documents:
    post:
      tags:
        - Documents
      operationId: createDocument
      summary: Upload a document
      description: "Uploads content and registers metadata in one multipart request with two parts: a JSON metadata part and
        the file part. At least one CUSTOMER or LOAN link is required. The server derives the checksum and content type;
        content is virus-scanned before it can be downloaded, and rejected content is quarantined and deleted. Marking a
        document sensitive requires the sensitive read permission."
      x-permission: CREATE_LMS_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 1204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          multipart/form-data:
            schema:
              type: object
              required:
                - metadata
                - file
              properties:
                metadata:
                  type: object
                  description: JSON metadata part.
                  required:
                    - title
                    - documentType
                    - sensitive
                    - links
                  properties:
                    title:
                      type: string
                    documentType:
                      type: string
                    sensitive:
                      type: boolean
                    links:
                      type: array
                      items:
                        type: object
                        required:
                          - targetType
                          - targetRef
                        properties:
                          targetType:
                            type: string
                          targetRef:
                            type: string
                file:
                  type: string
                  format: binary
                  description: Content bytes; the server derives the checksum and content type.
            example:
              metadata:
                title: Pay statement — April
                documentType: INCOME_EVIDENCE
                sensitive: false
                links:
                  - targetType: LOAN
                    targetRef: "7204"
              file: (binary content)
  /v1/documents/{documentId}:
    get:
      tags:
        - Documents
      operationId: getDocument
      summary: Retrieve document metadata
      description: Returns metadata, scan status, checksum, and active links. Sensitive documents additionally require the
        sensitive read permission.
      x-permission: READ_LMS_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - documentId
                  - documentRef
                  - documentType
                  - title
                  - origin
                  - originalFileName
                  - contentType
                  - contentLength
                  - checksumSha256
                  - scanStatus
                  - status
                  - sensitive
                  - createdAt
                  - links
                properties:
                  documentId:
                    type: integer
                  documentRef:
                    type: string
                  documentType:
                    type: string
                  title:
                    type: string
                  origin:
                    type: string
                  originalFileName:
                    type: string
                  contentType:
                    type: string
                  contentLength:
                    type: integer
                  checksumSha256:
                    type: string
                  scanStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  sensitive:
                    type: boolean
                  createdAt:
                    type: string
                    format: date-time
                  links:
                    type: array
                    items:
                      type: object
                      required:
                        - linkId
                        - targetType
                        - targetRef
                        - active
                      properties:
                        linkId:
                          type: integer
                        targetType:
                          type: string
                        targetRef:
                          type: string
                        active:
                          type: boolean
              example:
                documentId: 1204
                documentRef: doc_4f2a9c1b8d3e5a7c9b1d
                documentType: INCOME_EVIDENCE
                title: Pay statement — April
                origin: STAFF_UPLOAD
                originalFileName: pay-statement-april.pdf
                contentType: application/pdf
                contentLength: 184220
                checksumSha256: 2d8c1f0e5b7a4c6d8e0f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b188a
                scanStatus: CLEAN
                status: ACTIVE
                sensitive: false
                createdAt: 2027-05-01T10:40:00Z
                links:
                  - linkId: 61
                    targetType: LOAN
                    targetRef: "7204"
                    active: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Documents
      operationId: updateDocument
      summary: Update document metadata
      description: Updates title, description, or the sensitive flag. Content, origin, and checksum are immutable; replacement
        content is a new document that supersedes this one.
      x-permission: UPDATE_LMS_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - title
                      - sensitive
                    properties:
                      title:
                        type: string
                      sensitive:
                        type: boolean
              example:
                resourceId: 1204
                changes:
                  title: Pay statement — April 2027
                  sensitive: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - title
                - sensitive
              properties:
                title:
                  type: string
                sensitive:
                  type: boolean
              example:
                title: Pay statement — April 2027
                sensitive: true
            example:
              title: Pay statement — April 2027
              sensitive: true
  /v1/documents/{documentId}/content:
    get:
      tags:
        - Documents
      operationId: downloadDocumentContent
      summary: Download document content
      description: Streams the original bytes as an attachment after re-verifying the stored checksum. Only CLEAN-scanned
        documents are downloadable; the response is never cached.
      x-permission: READ_LMS_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
      responses:
        "200":
          description: Original content as an attachment.
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/documents/{documentId}/history:
    get:
      tags:
        - Documents
      operationId: listDocumentHistory
      summary: List document history
      description: Returns the document’s change events — creation, metadata updates, link changes, archive — newest first.
      x-permission: READ_LMS_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - action
                        - occurredAt
                        - actorUsername
                        - correlationId
                      properties:
                        action:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        actorUsername:
                          type: string
                        correlationId:
                          type: string
              example:
                items:
                  - action: DOCUMENT_CREATED
                    occurredAt: 2027-05-01T10:40:00Z
                    actorUsername: ana.alvarez
                    correlationId: corr_01JZ7M5KX9
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/documents/{documentId}/links:
    post:
      tags:
        - Documents
      operationId: addDocumentLink
      summary: Add a document link
      description: Links the document to another customer or loan.
      x-permission: UPDATE_LMS_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 1204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - targetType
                - targetRef
              properties:
                targetType:
                  type: string
                targetRef:
                  type: string
              example:
                targetType: CUSTOMER
                targetRef: "412"
            example:
              targetType: CUSTOMER
              targetRef: "412"
  /v1/documents/{documentId}/links/{linkId}/remove:
    post:
      tags:
        - Documents
      operationId: removeDocumentLink
      summary: Remove a document link
      description: Deactivates one link with an optional reason; the link row and its removal are retained.
      x-permission: UPDATE_LMS_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
        - name: linkId
          in: path
          required: true
          description: Stable opaque link identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 1204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
              example:
                reasonCode: LINKED_IN_ERROR
            example:
              reasonCode: LINKED_IN_ERROR
  /v1/documents/{documentId}/archive:
    post:
      tags:
        - Documents
      operationId: archiveDocument
      summary: Archive a document
      description: Archives the document with no request body. Idempotent; content and history are retained.
      x-permission: ARCHIVE_LMS_DOCUMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: documentId
          in: path
          required: true
          description: Stable opaque document identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 1204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/customers/{customerId}/documents:
    get:
      tags:
        - Documents
      operationId: listCustomerDocuments
      summary: List customer documents
      description: Lists documents actively linked to the customer, newest first.
      x-permission: READ_LMS_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - documentRef
                        - documentType
                        - title
                        - origin
                        - originalFileName
                        - contentType
                        - contentLength
                        - checksumSha256
                        - scanStatus
                        - status
                        - sensitive
                        - createdAt
                      properties:
                        documentId:
                          type: integer
                        documentRef:
                          type: string
                        documentType:
                          type: string
                        title:
                          type: string
                        origin:
                          type: string
                        originalFileName:
                          type: string
                        contentType:
                          type: string
                        contentLength:
                          type: integer
                        checksumSha256:
                          type: string
                        scanStatus:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        sensitive:
                          type: boolean
                        createdAt:
                          type: string
                          format: date-time
              example:
                items:
                  - documentId: 1204
                    documentRef: doc_4f2a9c1b8d3e5a7c9b1d
                    documentType: INCOME_EVIDENCE
                    title: Pay statement — April
                    origin: STAFF_UPLOAD
                    originalFileName: pay-statement-april.pdf
                    contentType: application/pdf
                    contentLength: 184220
                    checksumSha256: 2d8c1f0e5b7a4c6d8e0f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b188a
                    scanStatus: CLEAN
                    status: ACTIVE
                    sensitive: false
                    createdAt: 2027-05-01T10:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/documents:
    get:
      tags:
        - Documents
      operationId: listLoanDocuments
      summary: List loan documents
      description: Lists documents actively linked to the loan, newest first, including system-generated statements.
      x-permission: READ_LMS_DOCUMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - documentId
                        - documentRef
                        - documentType
                        - title
                        - origin
                        - originalFileName
                        - contentType
                        - contentLength
                        - checksumSha256
                        - scanStatus
                        - status
                        - sensitive
                        - createdAt
                      properties:
                        documentId:
                          type: integer
                        documentRef:
                          type: string
                        documentType:
                          type: string
                        title:
                          type: string
                        origin:
                          type: string
                        originalFileName:
                          type: string
                        contentType:
                          type: string
                        contentLength:
                          type: integer
                        checksumSha256:
                          type: string
                        scanStatus:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        sensitive:
                          type: boolean
                        createdAt:
                          type: string
                          format: date-time
              example:
                items:
                  - documentId: 1204
                    documentRef: doc_4f2a9c1b8d3e5a7c9b1d
                    documentType: INCOME_EVIDENCE
                    title: Pay statement — April
                    origin: STAFF_UPLOAD
                    originalFileName: pay-statement-april.pdf
                    contentType: application/pdf
                    contentLength: 184220
                    checksumSha256: 2d8c1f0e5b7a4c6d8e0f2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b188a
                    scanStatus: CLEAN
                    status: ACTIVE
                    sensitive: false
                    createdAt: 2027-05-01T10:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/notes:
    post:
      tags:
        - Notes
      operationId: createCustomerNote
      summary: Create a customer note
      description: Creates a note as revision one of an immutable revision chain. Marking a note sensitive requires the
        sensitive read permission; notes never trigger borrower communication.
      x-permission: CREATE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - body
                - sensitive
                - pinned
              properties:
                body:
                  type: string
                sensitive:
                  type: boolean
                pinned:
                  type: boolean
              example:
                body: Maya requested email delivery for the payoff figure.
                sensitive: false
                pinned: false
            example:
              body: Maya requested email delivery for the payoff figure.
              sensitive: false
              pinned: false
    get:
      tags:
        - Notes
      operationId: listCustomerNotes
      summary: List customer notes
      description: Lists note markers — status, flags, and redaction state — pinned first, newest first. Bodies are read one
        note at a time.
      x-permission: READ_LMS_NOTE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - noteId
                        - noteRef
                        - status
                        - sensitive
                        - pinned
                        - flagged
                        - redactionState
                      properties:
                        noteId:
                          type: integer
                        noteRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        sensitive:
                          type: boolean
                        pinned:
                          type: boolean
                        flagged:
                          type: boolean
                        redactionState:
                          type: string
              example:
                items:
                  - noteId: 802
                    noteRef: note_9c1d3e5f7a9b1c3d5e7f
                    status: ACTIVE
                    sensitive: false
                    pinned: false
                    flagged: false
                    redactionState: NONE
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/notes:
    post:
      tags:
        - Notes
      operationId: createLoanNote
      summary: Create a loan note
      description: Creates a note as revision one of an immutable revision chain. Marking a note sensitive requires the
        sensitive read permission; notes never trigger borrower communication.
      x-permission: CREATE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - body
                - sensitive
                - pinned
              properties:
                body:
                  type: string
                sensitive:
                  type: boolean
                pinned:
                  type: boolean
              example:
                body: Maya requested email delivery for the payoff figure.
                sensitive: false
                pinned: false
            example:
              body: Maya requested email delivery for the payoff figure.
              sensitive: false
              pinned: false
    get:
      tags:
        - Notes
      operationId: listLoanNotes
      summary: List loan notes
      description: Lists note markers — status, flags, and redaction state — pinned first, newest first. Bodies are read one
        note at a time.
      x-permission: READ_LMS_NOTE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - noteId
                        - noteRef
                        - status
                        - sensitive
                        - pinned
                        - flagged
                        - redactionState
                      properties:
                        noteId:
                          type: integer
                        noteRef:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        sensitive:
                          type: boolean
                        pinned:
                          type: boolean
                        flagged:
                          type: boolean
                        redactionState:
                          type: string
              example:
                items:
                  - noteId: 802
                    noteRef: note_9c1d3e5f7a9b1c3d5e7f
                    status: ACTIVE
                    sensitive: false
                    pinned: false
                    flagged: false
                    redactionState: NONE
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/notes/{noteId}:
    get:
      tags:
        - Notes
      operationId: getNote
      summary: Retrieve a note
      description: Returns the note with its current revision body. Sensitive bodies require the sensitive read permission; a
        redacted note returns a redaction placeholder and its prior content is never served again.
      x-permission: READ_LMS_NOTE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - noteId
                  - noteRef
                  - status
                  - sensitive
                  - pinned
                  - flagged
                  - redactionState
                  - body
                properties:
                  noteId:
                    type: integer
                  noteRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  sensitive:
                    type: boolean
                  pinned:
                    type: boolean
                  flagged:
                    type: boolean
                  redactionState:
                    type: string
                  body:
                    type: string
              example:
                noteId: 802
                noteRef: note_9c1d3e5f7a9b1c3d5e7f
                status: ACTIVE
                sensitive: false
                pinned: false
                flagged: false
                redactionState: NONE
                body: Maya requested email delivery for the payoff figure.
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Notes
      operationId: reviseNote
      summary: Revise a note
      description: Appends a new content revision with an optional change reason. The original revision is never edited or
        deleted; redacted notes cannot be revised.
      x-permission: UPDATE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - body
                - changeReason
              properties:
                body:
                  type: string
                changeReason:
                  type: string
              example:
                body: Maya requested secure-message delivery for the payoff figure.
                changeReason: Channel corrected.
            example:
              body: Maya requested secure-message delivery for the payoff figure.
              changeReason: Channel corrected.
  /v1/notes/{noteId}/history:
    get:
      tags:
        - Notes
      operationId: listNoteHistory
      summary: List note revisions
      description: Returns revision metadata newest first — revision number, type, and reasons. Revision bodies never appear
        in history.
      x-permission: READ_LMS_NOTE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - revisionNo
                        - revisionType
                        - changeReason
                        - occurredAt
                      properties:
                        revisionNo:
                          type: integer
                        revisionType:
                          type: string
                        changeReason:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
              example:
                items:
                  - revisionNo: 2
                    revisionType: CONTENT
                    changeReason: Channel corrected.
                    occurredAt: 2026-09-20T10:05:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/notes/{noteId}/links:
    post:
      tags:
        - Notes
      operationId: addNoteLink
      summary: Add a note link
      description: Links the note to another customer or loan.
      x-permission: UPDATE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - targetType
                - targetRef
              properties:
                targetType:
                  type: string
                targetRef:
                  type: string
              example:
                targetType: CUSTOMER
                targetRef: "412"
            example:
              targetType: CUSTOMER
              targetRef: "412"
  /v1/notes/{noteId}/links/{linkId}/remove:
    post:
      tags:
        - Notes
      operationId: removeNoteLink
      summary: Remove a note link
      description: Deactivates one link; the link row and its removal are retained.
      x-permission: UPDATE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
        - name: linkId
          in: path
          required: true
          description: Stable opaque link identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/notes/{noteId}/archive:
    post:
      tags:
        - Notes
      operationId: archiveNote
      summary: Archive a note
      description: Archives the note with no request body. Idempotent; revisions are retained.
      x-permission: ARCHIVE_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/notes/{noteId}/redact:
    post:
      tags:
        - Notes
      operationId: redactNote
      summary: Redact a note
      description: Permanently redacts the note’s content with a required reason. A redaction revision is appended, every read
        thereafter returns a placeholder, and redaction cannot be undone.
      x-permission: REDACT_LMS_NOTE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: noteId
          in: path
          required: true
          description: Stable opaque note identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 802
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - redactionReason
              properties:
                redactionReason:
                  type: string
              example:
                redactionReason: Contained payment card digits.
            example:
              redactionReason: Contained payment card digits.
  /v1/form-definitions:
    post:
      tags:
        - Forms
      operationId: createFormDefinition
      summary: Create a form definition
      description: Creates a draft definition for a CUSTOMER or LOAN target with SINGLE or MULTIPLE entry mode and a typed
        field schema. Creation atomically registers the form’s derived read, write, and delete permissions from its
        immutable key.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - formKey
                - targetType
                - entryMode
                - name
                - schema
              properties:
                formKey:
                  type: string
                targetType:
                  type: string
                entryMode:
                  type: string
                name:
                  type: string
                schema:
                  type: object
                  required:
                    - sections
                  properties:
                    sections:
                      type: array
                      items:
                        type: object
                        required:
                          - fields
                        properties:
                          fields:
                            type: array
                            items:
                              type: object
                              required:
                                - fieldKey
                                - dataType
                                - required
                                - options
                              properties:
                                fieldKey:
                                  type: string
                                dataType:
                                  type: string
                                required:
                                  type: boolean
                                options:
                                  type: array
                                  items:
                                    type: object
                                    required:
                                      - code
                                      - label
                                    properties:
                                      code:
                                        type: string
                                      label:
                                        type: string
              example:
                formKey: consumer_income
                targetType: CUSTOMER
                entryMode: SINGLE
                name: Consumer income
                schema:
                  sections:
                    - fields:
                        - fieldKey: employment_status
                          dataType: SINGLE_SELECT
                          required: true
                          options:
                            - code: EMPLOYED
                              label: Employed
                            - code: SELF_EMPLOYED
                              label: Self-employed
                            - code: RETIRED
                              label: Retired
                        - fieldKey: gross_monthly_income
                          dataType: DECIMAL
                          required: true
            example:
              formKey: consumer_income
              targetType: CUSTOMER
              entryMode: SINGLE
              name: Consumer income
              schema:
                sections:
                  - fields:
                      - fieldKey: employment_status
                        dataType: SINGLE_SELECT
                        required: true
                        options:
                          - code: EMPLOYED
                            label: Employed
                          - code: SELF_EMPLOYED
                            label: Self-employed
                          - code: RETIRED
                            label: Retired
                      - fieldKey: gross_monthly_income
                        dataType: DECIMAL
                        required: true
    get:
      tags:
        - Forms
      operationId: listFormDefinitions
      summary: List form definitions
      description: Lists definitions with target type, entry mode, and lifecycle status, ordered by form key.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - formKey
                        - targetType
                        - entryMode
                        - status
                        - name
                      properties:
                        formKey:
                          type: string
                        targetType:
                          type: string
                        entryMode:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        name:
                          type: string
              example:
                items:
                  - formKey: consumer_income
                    targetType: CUSTOMER
                    entryMode: SINGLE
                    status: PUBLISHED
                    name: Consumer income
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/form-definitions/{formKey}:
    get:
      tags:
        - Forms
      operationId: getFormDefinition
      summary: Retrieve a form definition
      description: Returns the definition with its current publication, any working draft, and the durable field registry with
        active flags.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - formKey
                  - targetType
                  - entryMode
                  - status
                  - name
                  - currentPublication
                  - fields
                properties:
                  formKey:
                    type: string
                  targetType:
                    type: string
                  entryMode:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  name:
                    type: string
                  currentPublication:
                    type: object
                    required:
                      - publicationId
                      - name
                      - schema
                      - publishedAt
                    properties:
                      publicationId:
                        type: integer
                      name:
                        type: string
                      schema:
                        type: object
                        required:
                          - sections
                        properties:
                          sections:
                            type: array
                            items:
                              type: object
                              required:
                                - fields
                              properties:
                                fields:
                                  type: array
                                  items:
                                    type: object
                                    required:
                                      - fieldKey
                                      - dataType
                                      - required
                                      - options
                                    properties:
                                      fieldKey:
                                        type: string
                                      dataType:
                                        type: string
                                      required:
                                        type: boolean
                                      options:
                                        type: array
                                        items:
                                          type: object
                                          required:
                                            - code
                                            - label
                                          properties:
                                            code:
                                              type: string
                                            label:
                                              type: string
                      publishedAt:
                        type: string
                        format: date-time
                  fields:
                    type: array
                    items:
                      type: object
                      required:
                        - fieldKey
                        - dataType
                        - active
                      properties:
                        fieldKey:
                          type: string
                        dataType:
                          type: string
                        active:
                          type: boolean
              example:
                formKey: consumer_income
                targetType: CUSTOMER
                entryMode: SINGLE
                status: PUBLISHED
                name: Consumer income
                currentPublication:
                  publicationId: 4
                  name: Consumer income
                  schema:
                    sections:
                      - fields:
                          - fieldKey: employment_status
                            dataType: SINGLE_SELECT
                            required: true
                            options:
                              - code: EMPLOYED
                                label: Employed
                              - code: SELF_EMPLOYED
                                label: Self-employed
                              - code: RETIRED
                                label: Retired
                          - fieldKey: gross_monthly_income
                            dataType: DECIMAL
                            required: true
                  publishedAt: 2026-07-01T00:00:00Z
                fields:
                  - fieldKey: employment_status
                    dataType: SINGLE_SELECT
                    active: true
                  - fieldKey: gross_monthly_income
                    dataType: DECIMAL
                    active: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/form-definitions/{formKey}/draft:
    put:
      tags:
        - Forms
      operationId: updateFormDefinitionDraft
      summary: Replace the working draft
      description: Replaces the definition’s single mutable draft in place. Drafts do not affect entries until published.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
                - schema
              properties:
                name:
                  type: string
                schema:
                  type: object
                  required:
                    - sections
                  properties:
                    sections:
                      type: array
                      items:
                        type: object
                        required:
                          - fields
                        properties:
                          fields:
                            type: array
                            items:
                              type: object
                              required:
                                - fieldKey
                                - dataType
                                - required
                                - options
                              properties:
                                fieldKey:
                                  type: string
                                dataType:
                                  type: string
                                required:
                                  type: boolean
                                options:
                                  type: array
                                  items:
                                    type: object
                                    required:
                                      - code
                                      - label
                                    properties:
                                      code:
                                        type: string
                                      label:
                                        type: string
              example:
                name: Consumer income
                schema:
                  sections:
                    - fields:
                        - fieldKey: employment_status
                          dataType: SINGLE_SELECT
                          required: true
                          options:
                            - code: EMPLOYED
                              label: Employed
                            - code: SELF_EMPLOYED
                              label: Self-employed
                            - code: RETIRED
                              label: Retired
                        - fieldKey: gross_monthly_income
                          dataType: DECIMAL
                          required: true
            example:
              name: Consumer income
              schema:
                sections:
                  - fields:
                      - fieldKey: employment_status
                        dataType: SINGLE_SELECT
                        required: true
                        options:
                          - code: EMPLOYED
                            label: Employed
                          - code: SELF_EMPLOYED
                            label: Self-employed
                          - code: RETIRED
                            label: Retired
                      - fieldKey: gross_monthly_income
                        dataType: DECIMAL
                        required: true
  /v1/form-definitions/{formKey}/publish:
    post:
      tags:
        - Forms
      operationId: publishFormDefinition
      summary: Publish a form definition
      description: Publishes the pending draft as an immutable publication and makes it the active version. Field keys keep
        their types forever — a type change is rejected — and a draft identical to the current publication publishes as
        a no-op.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/form-definitions/{formKey}/retire:
    post:
      tags:
        - Forms
      operationId: retireFormDefinition
      summary: Retire a form definition
      description: Retires the definition with a required reason. Existing entries remain readable; new entries are rejected.
        The derived permissions are retained.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: Superseded by consumer_income_v2.
            example:
              reason: Superseded by consumer_income_v2.
  /v1/form-definitions/{formKey}/history:
    get:
      tags:
        - Forms
      operationId: listFormDefinitionHistory
      summary: List form-definition history
      description: Returns creation, publication, and retirement events, newest first. Draft saves are not events.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum events to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: action
          in: query
          required: false
          description: Filter by event action.
          schema:
            type: string
            enum:
              - CREATED
              - PUBLISHED
              - RETIRED
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - historyId
                        - action
                        - occurredAt
                        - actor
                      properties:
                        historyId:
                          type: string
                        action:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
                        actor:
                          type: object
                          required:
                            - id
                            - username
                            - firstName
                            - lastName
                          properties:
                            id:
                              type: integer
                            username:
                              type: string
                            firstName:
                              type: string
                            lastName:
                              type: string
              example:
                items:
                  - historyId: fdh_p4
                    action: PUBLISHED
                    occurredAt: 2026-07-01T00:00:00Z
                    actor:
                      id: 9
                      username: ana.alvarez
                      firstName: Ana
                      lastName: Alvarez
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/form-definitions/{formKey}/history/{historyId}:
    get:
      tags:
        - Forms
      operationId: getFormDefinitionHistoryEvent
      summary: Retrieve a form-definition event
      description: Returns one lifecycle event; publication events include the exact schema that was published.
      x-permission: ADMIN_LMS_FORM_DEFINITION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: historyId
          in: path
          required: true
          description: Stable opaque history identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - historyId
                  - action
                  - occurredAt
                  - name
                  - schema
                properties:
                  historyId:
                    type: string
                  action:
                    type: string
                  occurredAt:
                    type: string
                    format: date-time
                  name:
                    type: string
                  schema:
                    type: object
                    required:
                      - sections
                    properties:
                      sections:
                        type: array
                        items:
                          type: object
                          required:
                            - fields
                          properties:
                            fields:
                              type: array
                              items:
                                type: object
                                required:
                                  - fieldKey
                                  - dataType
                                  - required
                                  - options
                                properties:
                                  fieldKey:
                                    type: string
                                  dataType:
                                    type: string
                                  required:
                                    type: boolean
                                  options:
                                    type: array
                                    items:
                                      type: object
                                      required:
                                        - code
                                        - label
                                      properties:
                                        code:
                                          type: string
                                        label:
                                          type: string
              example:
                historyId: fdh_p4
                action: PUBLISHED
                occurredAt: 2026-07-01T00:00:00Z
                name: Consumer income
                schema:
                  sections:
                    - fields:
                        - fieldKey: employment_status
                          dataType: SINGLE_SELECT
                          required: true
                          options:
                            - code: EMPLOYED
                              label: Employed
                            - code: SELF_EMPLOYED
                              label: Self-employed
                            - code: RETIRED
                              label: Retired
                        - fieldKey: gross_monthly_income
                          dataType: DECIMAL
                          required: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/customers/{customerId}/forms/{formKey}/entries:
    post:
      tags:
        - Forms
      operationId: createCustomerFormEntry
      summary: Submit a customer form entry
      description: Validates typed answers against the form’s active publication and stores the entry. Required active fields
        must be present; option codes must exist. SINGLE-mode forms allow one current entry per target — a second create
        conflicts with the existing entry.
      x-permission: WRITE_LMS_FORM_<KEY>
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - entryId
                  - formKey
                  - targetId
                  - answers
                  - createdAt
                  - lastModifiedAt
                properties:
                  entryId:
                    type: integer
                  formKey:
                    type: string
                  targetId:
                    type: string
                  answers:
                    type: object
                    required:
                      - employment_status
                      - gross_monthly_income
                    properties:
                      employment_status:
                        type: string
                      gross_monthly_income:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                entryId: 5501
                formKey: consumer_income
                targetId: "412"
                answers:
                  employment_status: EMPLOYED
                  gross_monthly_income: "6400"
                createdAt: 2026-08-11T15:40:00Z
                lastModifiedAt: 2026-08-11T15:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - answers
              properties:
                answers:
                  type: object
                  required:
                    - employment_status
                    - gross_monthly_income
                  properties:
                    employment_status:
                      type: string
                    gross_monthly_income:
                      type: string
              example:
                answers:
                  employment_status: EMPLOYED
                  gross_monthly_income: "6400"
            example:
              answers:
                employment_status: EMPLOYED
                gross_monthly_income: "6400"
    get:
      tags:
        - Forms
      operationId: listCustomerFormEntries
      summary: List customer form entries
      description: Lists current entries for this form and target with limit/offset paging, sorting, and creation-time ranges.
      x-permission: READ_LMS_FORM_<KEY>
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: customerId
          in: path
          required: true
          description: Stable opaque customer identifier.
          schema:
            type: string
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Sort field.
          schema:
            type: string
            enum:
              - createdAt
              - lastModifiedAt
            default: createdAt
        - name: order
          in: query
          required: false
          description: Sort direction.
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - name: createdFrom
          in: query
          required: false
          description: Inclusive creation lower bound; supply with createdTo.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive creation upper bound.
          schema:
            type: string
            format: date-time
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - limit
                  - offset
                  - items
                properties:
                  limit:
                    type: integer
                  offset:
                    type: integer
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - entryId
                        - formKey
                        - targetId
                        - answers
                        - createdAt
                        - lastModifiedAt
                      properties:
                        entryId:
                          type: integer
                        formKey:
                          type: string
                        targetId:
                          type: string
                        answers:
                          type: object
                          required:
                            - employment_status
                            - gross_monthly_income
                          properties:
                            employment_status:
                              type: string
                            gross_monthly_income:
                              type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                limit: 50
                offset: 0
                items:
                  - entryId: 5501
                    formKey: consumer_income
                    targetId: "412"
                    answers:
                      employment_status: EMPLOYED
                      gross_monthly_income: "6400"
                    createdAt: 2026-08-11T15:40:00Z
                    lastModifiedAt: 2026-08-11T15:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/forms/{formKey}/entries:
    post:
      tags:
        - Forms
      operationId: createLoanFormEntry
      summary: Submit a loan form entry
      description: Validates typed answers against the form’s active publication and stores the entry. Required active fields
        must be present; option codes must exist. SINGLE-mode forms allow one current entry per target — a second create
        conflicts with the existing entry.
      x-permission: WRITE_LMS_FORM_<KEY>
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - entryId
                  - formKey
                  - targetId
                  - answers
                  - createdAt
                  - lastModifiedAt
                properties:
                  entryId:
                    type: integer
                  formKey:
                    type: string
                  targetId:
                    type: string
                  answers:
                    type: object
                    required:
                      - employment_status
                      - gross_monthly_income
                    properties:
                      employment_status:
                        type: string
                      gross_monthly_income:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                entryId: 5501
                formKey: consumer_income
                targetId: "7204"
                answers:
                  employment_status: EMPLOYED
                  gross_monthly_income: "6400"
                createdAt: 2026-08-11T15:40:00Z
                lastModifiedAt: 2026-08-11T15:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - answers
              properties:
                answers:
                  type: object
                  required:
                    - employment_status
                    - gross_monthly_income
                  properties:
                    employment_status:
                      type: string
                    gross_monthly_income:
                      type: string
              example:
                answers:
                  employment_status: EMPLOYED
                  gross_monthly_income: "6400"
            example:
              answers:
                employment_status: EMPLOYED
                gross_monthly_income: "6400"
    get:
      tags:
        - Forms
      operationId: listLoanFormEntries
      summary: List loan form entries
      description: Lists current entries for this form and target with limit/offset paging, sorting, and creation-time ranges.
      x-permission: READ_LMS_FORM_<KEY>
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: formKey
          in: path
          required: true
          description: Stable opaque formKey identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: sort
          in: query
          required: false
          description: Sort field.
          schema:
            type: string
            enum:
              - createdAt
              - lastModifiedAt
            default: createdAt
        - name: order
          in: query
          required: false
          description: Sort direction.
          schema:
            type: string
            enum:
              - asc
              - desc
            default: desc
        - name: createdFrom
          in: query
          required: false
          description: Inclusive creation lower bound; supply with createdTo.
          schema:
            type: string
            format: date-time
        - name: createdTo
          in: query
          required: false
          description: Exclusive creation upper bound.
          schema:
            type: string
            format: date-time
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - limit
                  - offset
                  - items
                properties:
                  limit:
                    type: integer
                  offset:
                    type: integer
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - entryId
                        - formKey
                        - targetId
                        - answers
                        - createdAt
                        - lastModifiedAt
                      properties:
                        entryId:
                          type: integer
                        formKey:
                          type: string
                        targetId:
                          type: string
                        answers:
                          type: object
                          required:
                            - employment_status
                            - gross_monthly_income
                          properties:
                            employment_status:
                              type: string
                            gross_monthly_income:
                              type: string
                        createdAt:
                          type: string
                          format: date-time
                        lastModifiedAt:
                          type: string
                          format: date-time
              example:
                limit: 50
                offset: 0
                items:
                  - entryId: 5501
                    formKey: consumer_income
                    targetId: "7204"
                    answers:
                      employment_status: EMPLOYED
                      gross_monthly_income: "6400"
                    createdAt: 2026-08-11T15:40:00Z
                    lastModifiedAt: 2026-08-11T15:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/form-entries/{entryId}:
    get:
      tags:
        - Forms
      operationId: getFormEntry
      summary: Retrieve a form entry
      description: Returns the entry with typed answers for active fields. Removed entries return 404.
      x-permission: READ_LMS_FORM_<KEY>
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: entryId
          in: path
          required: true
          description: Stable opaque entry identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - entryId
                  - formKey
                  - targetId
                  - answers
                  - createdAt
                  - lastModifiedAt
                properties:
                  entryId:
                    type: integer
                  formKey:
                    type: string
                  targetId:
                    type: string
                  answers:
                    type: object
                    required:
                      - employment_status
                      - gross_monthly_income
                    properties:
                      employment_status:
                        type: string
                      gross_monthly_income:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                entryId: 5501
                formKey: consumer_income
                targetId: "412"
                answers:
                  employment_status: EMPLOYED
                  gross_monthly_income: "6400"
                createdAt: 2026-08-11T15:40:00Z
                lastModifiedAt: 2026-08-11T15:40:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Forms
      operationId: updateFormEntry
      summary: Update a form entry
      description: "Replaces the complete answer set: omitted optional fields clear, and an identical replacement records no
        change. Field-level deltas are recorded in entry history."
      x-permission: WRITE_LMS_FORM_<KEY>
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: entryId
          in: path
          required: true
          description: Stable opaque entry identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - entryId
                  - formKey
                  - targetId
                  - answers
                  - createdAt
                  - lastModifiedAt
                properties:
                  entryId:
                    type: integer
                  formKey:
                    type: string
                  targetId:
                    type: string
                  answers:
                    type: object
                    required:
                      - employment_status
                      - gross_monthly_income
                    properties:
                      employment_status:
                        type: string
                      gross_monthly_income:
                        type: string
                  createdAt:
                    type: string
                    format: date-time
                  lastModifiedAt:
                    type: string
                    format: date-time
              example:
                entryId: 5501
                formKey: consumer_income
                targetId: "412"
                answers:
                  employment_status: SELF_EMPLOYED
                  gross_monthly_income: "7100"
                createdAt: 2026-08-11T15:40:00Z
                lastModifiedAt: 2027-02-02T09:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - answers
                - changeReason
              properties:
                answers:
                  type: object
                  required:
                    - employment_status
                    - gross_monthly_income
                  properties:
                    employment_status:
                      type: string
                    gross_monthly_income:
                      type: string
                changeReason:
                  type: string
              example:
                answers:
                  employment_status: SELF_EMPLOYED
                  gross_monthly_income: "7100"
                changeReason: Employment change reported.
            example:
              answers:
                employment_status: SELF_EMPLOYED
                gross_monthly_income: "7100"
              changeReason: Employment change reported.
    delete:
      tags:
        - Forms
      operationId: removeFormEntry
      summary: Remove a form entry
      description: Soft-removes the entry with a required reason. Idempotent; history is retained.
      x-permission: DELETE_LMS_FORM_<KEY>
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: entryId
          in: path
          required: true
          description: Stable opaque entry identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - entryId
                  - removedAt
                  - resourceId
                properties:
                  entryId:
                    type: integer
                  removedAt:
                    type: string
                    format: date-time
                  resourceId:
                    type: integer
              example:
                entryId: 5501
                removedAt: 2027-03-01T12:00:00Z
                resourceId: 5501
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reason
              properties:
                reason:
                  type: string
              example:
                reason: Captured against the wrong customer.
            example:
              reason: Captured against the wrong customer.
  /v1/form-entries/{entryId}/history:
    get:
      tags:
        - Forms
      operationId: listFormEntryHistory
      summary: List form-entry history
      description: Returns semantic entry events — created, answers updated with field-level deltas, removed — newest first.
      x-permission: READ_LMS_FORM_<KEY>
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: entryId
          in: path
          required: true
          description: Stable opaque entry identifier.
          schema:
            type: string
        - name: limit
          in: query
          required: false
          description: Maximum events to return.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - action
                        - publicationId
                        - changes
                        - reason
                        - actorDisplayName
                        - occurredAt
                      properties:
                        action:
                          type: string
                        publicationId:
                          type: integer
                        changes:
                          type: array
                          items:
                            type: object
                            required:
                              - fieldKey
                              - operation
                              - before
                              - after
                            properties:
                              fieldKey:
                                type: string
                              operation:
                                type: string
                              before:
                                type: string
                              after:
                                type: string
                        reason:
                          type: string
                        actorDisplayName:
                          type: string
                        occurredAt:
                          type: string
                          format: date-time
              example:
                items:
                  - action: ANSWERS_UPDATED
                    publicationId: 4
                    changes:
                      - fieldKey: employment_status
                        operation: SET
                        before: EMPLOYED
                        after: SELF_EMPLOYED
                    reason: Employment change reported.
                    actorDisplayName: Ana Alvarez
                    occurredAt: 2027-02-02T09:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/statements:
    get:
      tags:
        - Statements
      operationId: listStatements
      summary: List loan statements
      description: Lists the loan’s statements, newest due date first. Statements are generated by the scheduled statement job
        at the product’s lead time; there is no public generate operation. Superseded versions remain listed.
      x-permission: READ_LMS_STATEMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - items
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      required:
                        - statementId
                        - dueDate
                        - status
                        - generationTrigger
                        - templateVersion
                        - statementVersion
                        - createdAt
                      properties:
                        statementId:
                          type: integer
                        dueDate:
                          type: string
                          format: date
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        generationTrigger:
                          type: string
                        templateVersion:
                          type: string
                        statementVersion:
                          type: integer
                        createdAt:
                          type: string
                          format: date-time
              example:
                items:
                  - statementId: 7719
                    dueDate: 2026-10-12
                    status: COMPLETED
                    generationTrigger: SCHEDULED_JOB
                    templateVersion: stmt-v1
                    statementVersion: 1
                    createdAt: 2026-10-03T00:10:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/statements/{statementId}/download:
    get:
      tags:
        - Statements
      operationId: downloadStatement
      summary: Download a statement
      description: Streams the statement PDF as an attachment. Only COMPLETED statements are downloadable.
      x-permission: READ_LMS_STATEMENT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: statementId
          in: path
          required: true
          description: Stable opaque statement identifier.
          schema:
            type: string
      responses:
        "200":
          description: Statement PDF attachment.
          content:
            application/pdf:
              schema:
                type: string
                format: binary
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/statements/{statementId}/regenerate:
    post:
      tags:
        - Statements
      operationId: regenerateStatement
      summary: Regenerate a statement
      description: Creates a corrected replacement for a COMPLETED statement with a closed reason code —
        SOURCE_DATA_CORRECTION, TEMPLATE_CORRECTION, COMPLIANCE_CORRECTION, OPERATIONAL_RECOVERY, or OTHER (comment
        required). The source statement becomes SUPERSEDED only when the replacement completes.
      x-permission: REGENERATE_LMS_STATEMENT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: statementId
          in: path
          required: true
          description: Stable opaque statement identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 7720
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCode
                - comment
              properties:
                reasonCode:
                  type: string
                  description: Configured structured reason code.
                comment:
                  type: string
              example:
                reasonCode: SOURCE_DATA_CORRECTION
                comment: Reflects the corrected 2026-09-12 payment allocation.
            example:
              reasonCode: SOURCE_DATA_CORRECTION
              comment: Reflects the corrected 2026-09-12 payment allocation.
  /v1/charges:
    get:
      tags:
        - Charges
      operationId: listCharges
      summary: List charge definitions
      description: Returns loan charge definitions with their LendEasy classification. Definitions without a classification
        are reported as configurationStatus MISSING and cannot be attached to products or loans.
      x-permission: READ_LMS_CHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - name
                    - active
                    - penalty
                    - currency
                    - amount
                    - chargeTimeType
                    - chargeCalculationType
                    - lmsConfig
                    - configurationStatus
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    active:
                      type: boolean
                    penalty:
                      type: boolean
                    currency:
                      type: object
                      description: ISO 4217 currency code.
                      required:
                        - code
                      properties:
                        code:
                          type: string
                    amount:
                      type: integer
                      description: Decimal monetary amount encoded as a string.
                    chargeTimeType:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                    chargeCalculationType:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                    lmsConfig:
                      type: object
                      required:
                        - financeChargeFlag
                        - legalBasis
                      properties:
                        financeChargeFlag:
                          type: string
                        legalBasis:
                          type: string
                    configurationStatus:
                      type: string
              example:
                - id: 21
                  name: Late fee
                  active: true
                  penalty: true
                  currency:
                    code: USD
                  amount: 18
                  chargeTimeType:
                    id: 9
                    value: Overdue Installment Fee
                  chargeCalculationType:
                    id: 1
                    value: Flat
                  lmsConfig:
                    financeChargeFlag: EXCLUDED
                    legalBasis: CA Fin. Code §22307
                  configurationStatus: CONFIGURED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Charges
      operationId: createCharge
      summary: Create a charge definition
      description: "Creates a loan charge definition and its required LendEasy classification atomically. The body has two
        blocks: the native charge settings and lmsConfig with the Regulation Z finance-charge flag and legal basis."
      x-permission: CREATE_LMS_CHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 21
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fineract
                - lmsConfig
              properties:
                fineract:
                  type: object
                  required:
                    - name
                    - currencyCode
                    - amount
                    - chargeAppliesTo
                    - chargeTimeType
                    - chargeCalculationType
                    - penalty
                    - active
                  properties:
                    name:
                      type: string
                    currencyCode:
                      type: string
                    amount:
                      type: integer
                      description: Decimal monetary amount encoded as a string.
                    chargeAppliesTo:
                      type: integer
                    chargeTimeType:
                      type: integer
                    chargeCalculationType:
                      type: integer
                    penalty:
                      type: boolean
                    active:
                      type: boolean
                lmsConfig:
                  type: object
                  required:
                    - financeChargeFlag
                    - legalBasis
                  properties:
                    financeChargeFlag:
                      type: string
                    legalBasis:
                      type: string
              example:
                fineract:
                  name: Late fee
                  currencyCode: USD
                  amount: 18
                  chargeAppliesTo: 1
                  chargeTimeType: 9
                  chargeCalculationType: 1
                  penalty: true
                  active: true
                lmsConfig:
                  financeChargeFlag: EXCLUDED
                  legalBasis: CA Fin. Code §22307
            example:
              fineract:
                name: Late fee
                currencyCode: USD
                amount: 18
                chargeAppliesTo: 1
                chargeTimeType: 9
                chargeCalculationType: 1
                penalty: true
                active: true
              lmsConfig:
                financeChargeFlag: EXCLUDED
                legalBasis: CA Fin. Code §22307
  /v1/charges/template:
    get:
      tags:
        - Charges
      operationId: getChargeTemplate
      summary: Retrieve the charge template
      description: Returns the option catalogs for creating a charge definition, including the LendEasy finance-charge
        classification options.
      x-permission: READ_LMS_CHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - currencyOptions
                  - chargeCalculationTypeOptions
                  - chargeTimeTypeOptions
                  - lmsConfig
                properties:
                  currencyOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                      properties:
                        code:
                          type: string
                  chargeCalculationTypeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                  chargeTimeTypeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                  lmsConfig:
                    type: object
                    required:
                      - financeChargeFlagOptions
                    properties:
                      financeChargeFlagOptions:
                        type: array
                        items:
                          type: string
              example:
                currencyOptions:
                  - code: USD
                chargeCalculationTypeOptions:
                  - id: 1
                    value: Flat
                chargeTimeTypeOptions:
                  - id: 1
                    value: Disbursement
                lmsConfig:
                  financeChargeFlagOptions:
                    - FINANCE_CHARGE
                    - NOT_FINANCE_CHARGE
                    - EXCLUDED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/charges/{chargeId}:
    get:
      tags:
        - Charges
      operationId: getCharge
      summary: Retrieve a charge definition
      description: Returns one charge definition with its LendEasy classification.
      x-permission: READ_LMS_CHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: chargeId
          in: path
          required: true
          description: Stable opaque charge identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - name
                  - active
                  - penalty
                  - currency
                  - amount
                  - chargeTimeType
                  - chargeCalculationType
                  - lmsConfig
                  - configurationStatus
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  active:
                    type: boolean
                  penalty:
                    type: boolean
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  amount:
                    type: integer
                    description: Decimal monetary amount encoded as a string.
                  chargeTimeType:
                    type: object
                    required:
                      - id
                      - value
                    properties:
                      id:
                        type: integer
                      value:
                        type: string
                  chargeCalculationType:
                    type: object
                    required:
                      - id
                      - value
                    properties:
                      id:
                        type: integer
                      value:
                        type: string
                  lmsConfig:
                    type: object
                    required:
                      - financeChargeFlag
                      - legalBasis
                    properties:
                      financeChargeFlag:
                        type: string
                      legalBasis:
                        type: string
                  configurationStatus:
                    type: string
              example:
                id: 21
                name: Late fee
                active: true
                penalty: true
                currency:
                  code: USD
                amount: 18
                chargeTimeType:
                  id: 9
                  value: Overdue Installment Fee
                chargeCalculationType:
                  id: 1
                  value: Flat
                lmsConfig:
                  financeChargeFlag: EXCLUDED
                  legalBasis: CA Fin. Code §22307
                configurationStatus: CONFIGURED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Charges
      operationId: updateCharge
      summary: Update a charge definition
      description: Replaces the charge definition aggregate. The finance-charge classification is immutable once set — only
        the legal basis may be corrected; APR treatment never changes retroactively.
      x-permission: UPDATE_LMS_CHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: chargeId
          in: path
          required: true
          description: Stable opaque charge identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - amount
                    properties:
                      amount:
                        type: integer
                        description: Decimal monetary amount encoded as a string.
              example:
                resourceId: 21
                changes:
                  amount: 20
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fineract
                - lmsConfig
              properties:
                fineract:
                  type: object
                  required:
                    - name
                    - currencyCode
                    - amount
                    - chargeAppliesTo
                    - chargeTimeType
                    - chargeCalculationType
                    - penalty
                    - active
                  properties:
                    name:
                      type: string
                    currencyCode:
                      type: string
                    amount:
                      type: integer
                      description: Decimal monetary amount encoded as a string.
                    chargeAppliesTo:
                      type: integer
                    chargeTimeType:
                      type: integer
                    chargeCalculationType:
                      type: integer
                    penalty:
                      type: boolean
                    active:
                      type: boolean
                lmsConfig:
                  type: object
                  required:
                    - financeChargeFlag
                    - legalBasis
                  properties:
                    financeChargeFlag:
                      type: string
                    legalBasis:
                      type: string
              example:
                fineract:
                  name: Late fee
                  currencyCode: USD
                  amount: 20
                  chargeAppliesTo: 1
                  chargeTimeType: 9
                  chargeCalculationType: 1
                  penalty: true
                  active: true
                lmsConfig:
                  financeChargeFlag: EXCLUDED
                  legalBasis: CA Fin. Code §22307
            example:
              fineract:
                name: Late fee
                currencyCode: USD
                amount: 20
                chargeAppliesTo: 1
                chargeTimeType: 9
                chargeCalculationType: 1
                penalty: true
                active: true
              lmsConfig:
                financeChargeFlag: EXCLUDED
                legalBasis: CA Fin. Code §22307
  /v1/loanproducts:
    get:
      tags:
        - Loan products
      operationId: listLoanProducts
      summary: List loan products
      description: Returns loan products with their LendEasy configuration — product class, APR and statement policy. Products
        without configuration are reported as configurationStatus MISSING and cannot originate loans.
      x-permission: READ_LMS_PRODUCT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - name
                    - shortName
                    - status
                    - currency
                    - numberOfRepayments
                    - interestRatePerPeriod
                    - lmsConfig
                    - configurationStatus
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    shortName:
                      type: string
                    status:
                      type: string
                      description: Current normalized lifecycle state.
                    currency:
                      type: object
                      description: ISO 4217 currency code.
                      required:
                        - code
                      properties:
                        code:
                          type: string
                    numberOfRepayments:
                      type: integer
                    interestRatePerPeriod:
                      type: number
                    lmsConfig:
                      type: object
                      required:
                        - productClass
                        - aprEnabled
                        - aprRounding
                        - aprTolerancePolicy
                        - statementEnabled
                        - statementLeadDays
                      properties:
                        productClass:
                          type: string
                        aprEnabled:
                          type: boolean
                        aprRounding:
                          type: string
                        aprTolerancePolicy:
                          type: string
                        statementEnabled:
                          type: boolean
                        statementLeadDays:
                          type: integer
                    configurationStatus:
                      type: string
              example:
                - id: 3
                  name: Harbor 18-month personal loan
                  shortName: HBR18
                  status: loanProduct.active
                  currency:
                    code: USD
                  numberOfRepayments: 18
                  interestRatePerPeriod: 13.25
                  lmsConfig:
                    productClass: COVERED_CONSUMER
                    aprEnabled: true
                    aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                    aprTolerancePolicy: REGULAR
                    statementEnabled: true
                    statementLeadDays: 10
                  configurationStatus: CONFIGURED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Loan products
      operationId: createLoanProduct
      summary: Create a loan product
      description: "Creates a progressive loan product and its required LendEasy configuration atomically. The body has two
        blocks: the native product settings — progressive schedule, no interest recalculation, charges referenced by id
        — and lmsConfig with product class, APR policy, statement policy, and optional overpayment tolerance. The server
        owns the payment-allocation order."
      x-permission: CREATE_LMS_LOAN_PRODUCT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 3
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fineract
                - lmsConfig
              properties:
                fineract:
                  type: object
                  required:
                    - name
                    - shortName
                    - currencyCode
                    - principal
                    - numberOfRepayments
                    - repaymentEvery
                    - repaymentFrequencyType
                    - interestRatePerPeriod
                    - interestRateFrequencyType
                    - amortizationType
                    - interestType
                    - interestCalculationPeriodType
                    - transactionProcessingStrategyCode
                    - loanScheduleType
                    - isInterestRecalculationEnabled
                    - accountingRule
                    - charges
                  properties:
                    name:
                      type: string
                    shortName:
                      type: string
                    currencyCode:
                      type: string
                    principal:
                      type: integer
                    numberOfRepayments:
                      type: integer
                    repaymentEvery:
                      type: integer
                    repaymentFrequencyType:
                      type: integer
                    interestRatePerPeriod:
                      type: number
                    interestRateFrequencyType:
                      type: integer
                    amortizationType:
                      type: integer
                    interestType:
                      type: integer
                    interestCalculationPeriodType:
                      type: integer
                    transactionProcessingStrategyCode:
                      type: string
                    loanScheduleType:
                      type: string
                    isInterestRecalculationEnabled:
                      type: boolean
                    accountingRule:
                      type: integer
                    charges:
                      type: array
                      items:
                        type: object
                        required:
                          - id
                        properties:
                          id:
                            type: integer
                lmsConfig:
                  type: object
                  required:
                    - productClass
                    - aprEnabled
                    - aprRounding
                    - aprTolerancePolicy
                    - statementEnabled
                    - statementLeadDays
                  properties:
                    productClass:
                      type: string
                    aprEnabled:
                      type: boolean
                    aprRounding:
                      type: string
                    aprTolerancePolicy:
                      type: string
                    statementEnabled:
                      type: boolean
                    statementLeadDays:
                      type: integer
              example:
                fineract:
                  name: Harbor 18-month personal loan
                  shortName: HBR18
                  currencyCode: USD
                  principal: 8400
                  numberOfRepayments: 18
                  repaymentEvery: 1
                  repaymentFrequencyType: 2
                  interestRatePerPeriod: 13.25
                  interestRateFrequencyType: 3
                  amortizationType: 1
                  interestType: 0
                  interestCalculationPeriodType: 1
                  transactionProcessingStrategyCode: advanced-payment-allocation-strategy
                  loanScheduleType: PROGRESSIVE
                  isInterestRecalculationEnabled: false
                  accountingRule: 1
                  charges:
                    - id: 12
                lmsConfig:
                  productClass: COVERED_CONSUMER
                  aprEnabled: true
                  aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                  aprTolerancePolicy: REGULAR
                  statementEnabled: true
                  statementLeadDays: 10
            example:
              fineract:
                name: Harbor 18-month personal loan
                shortName: HBR18
                currencyCode: USD
                principal: 8400
                numberOfRepayments: 18
                repaymentEvery: 1
                repaymentFrequencyType: 2
                interestRatePerPeriod: 13.25
                interestRateFrequencyType: 3
                amortizationType: 1
                interestType: 0
                interestCalculationPeriodType: 1
                transactionProcessingStrategyCode: advanced-payment-allocation-strategy
                loanScheduleType: PROGRESSIVE
                isInterestRecalculationEnabled: false
                accountingRule: 1
                charges:
                  - id: 12
              lmsConfig:
                productClass: COVERED_CONSUMER
                aprEnabled: true
                aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                aprTolerancePolicy: REGULAR
                statementEnabled: true
                statementLeadDays: 10
  /v1/loanproducts/template:
    get:
      tags:
        - Loan products
      operationId: getLoanProductTemplate
      summary: Retrieve the product template
      description: Returns the option catalogs for creating a loan product, including LendEasy product-class, APR-rounding,
        and APR-tolerance options.
      x-permission: READ_LMS_PRODUCT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - currencyOptions
                  - amortizationTypeOptions
                  - interestTypeOptions
                  - lmsConfig
                properties:
                  currencyOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - code
                      properties:
                        code:
                          type: string
                  amortizationTypeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                  interestTypeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                  lmsConfig:
                    type: object
                    required:
                      - productClassOptions
                      - aprTolerancePolicyOptions
                      - aprRoundingOptions
                    properties:
                      productClassOptions:
                        type: array
                        items:
                          type: string
                      aprTolerancePolicyOptions:
                        type: array
                        items:
                          type: string
                      aprRoundingOptions:
                        type: array
                        items:
                          type: string
              example:
                currencyOptions:
                  - code: USD
                amortizationTypeOptions:
                  - id: 1
                    value: Equal installments
                interestTypeOptions:
                  - id: 0
                    value: Declining Balance
                lmsConfig:
                  productClassOptions:
                    - COVERED_CONSUMER
                    - MERCHANT_ADVANCE
                  aprTolerancePolicyOptions:
                    - REGULAR
                    - IRREGULAR
                  aprRoundingOptions:
                    - NEAREST_0_01_PERCENT_HALF_UP
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loanproducts/{productId}:
    get:
      tags:
        - Loan products
      operationId: getLoanProduct
      summary: Retrieve a loan product
      description: Returns one product with its LendEasy configuration.
      x-permission: READ_LMS_PRODUCT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: productId
          in: path
          required: true
          description: Stable opaque product identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - name
                  - shortName
                  - currency
                  - numberOfRepayments
                  - interestRatePerPeriod
                  - loanScheduleType
                  - lmsConfig
                  - configurationStatus
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  shortName:
                    type: string
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  numberOfRepayments:
                    type: integer
                  interestRatePerPeriod:
                    type: number
                  loanScheduleType:
                    type: object
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  lmsConfig:
                    type: object
                    required:
                      - productClass
                      - aprEnabled
                      - aprRounding
                      - aprTolerancePolicy
                      - statementEnabled
                      - statementLeadDays
                    properties:
                      productClass:
                        type: string
                      aprEnabled:
                        type: boolean
                      aprRounding:
                        type: string
                      aprTolerancePolicy:
                        type: string
                      statementEnabled:
                        type: boolean
                      statementLeadDays:
                        type: integer
                  configurationStatus:
                    type: string
              example:
                id: 3
                name: Harbor 18-month personal loan
                shortName: HBR18
                currency:
                  code: USD
                numberOfRepayments: 18
                interestRatePerPeriod: 13.25
                loanScheduleType:
                  code: PROGRESSIVE
                lmsConfig:
                  productClass: COVERED_CONSUMER
                  aprEnabled: true
                  aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                  aprTolerancePolicy: REGULAR
                  statementEnabled: true
                  statementLeadDays: 10
                configurationStatus: CONFIGURED
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Loan products
      operationId: updateLoanProduct
      summary: Update a loan product
      description: Replaces the product aggregate — native settings and LendEasy configuration together. Every referenced
        charge must exist and carry its own classification.
      x-permission: UPDATE_LMS_LOAN_PRODUCT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: productId
          in: path
          required: true
          description: Stable opaque product identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - interestRatePerPeriod
                    properties:
                      interestRatePerPeriod:
                        type: number
              example:
                resourceId: 3
                changes:
                  interestRatePerPeriod: 12.75
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - fineract
                - lmsConfig
              properties:
                fineract:
                  type: object
                  required:
                    - name
                    - shortName
                    - currencyCode
                    - principal
                    - numberOfRepayments
                    - repaymentEvery
                    - repaymentFrequencyType
                    - interestRatePerPeriod
                    - interestRateFrequencyType
                    - amortizationType
                    - interestType
                    - interestCalculationPeriodType
                    - transactionProcessingStrategyCode
                    - loanScheduleType
                    - isInterestRecalculationEnabled
                    - accountingRule
                    - charges
                  properties:
                    name:
                      type: string
                    shortName:
                      type: string
                    currencyCode:
                      type: string
                    principal:
                      type: integer
                    numberOfRepayments:
                      type: integer
                    repaymentEvery:
                      type: integer
                    repaymentFrequencyType:
                      type: integer
                    interestRatePerPeriod:
                      type: number
                    interestRateFrequencyType:
                      type: integer
                    amortizationType:
                      type: integer
                    interestType:
                      type: integer
                    interestCalculationPeriodType:
                      type: integer
                    transactionProcessingStrategyCode:
                      type: string
                    loanScheduleType:
                      type: string
                    isInterestRecalculationEnabled:
                      type: boolean
                    accountingRule:
                      type: integer
                    charges:
                      type: array
                      items:
                        type: object
                        required:
                          - id
                        properties:
                          id:
                            type: integer
                lmsConfig:
                  type: object
                  required:
                    - productClass
                    - aprEnabled
                    - aprRounding
                    - aprTolerancePolicy
                    - statementEnabled
                    - statementLeadDays
                  properties:
                    productClass:
                      type: string
                    aprEnabled:
                      type: boolean
                    aprRounding:
                      type: string
                    aprTolerancePolicy:
                      type: string
                    statementEnabled:
                      type: boolean
                    statementLeadDays:
                      type: integer
              example:
                fineract:
                  name: Harbor 18-month personal loan
                  shortName: HBR18
                  currencyCode: USD
                  principal: 8400
                  numberOfRepayments: 18
                  repaymentEvery: 1
                  repaymentFrequencyType: 2
                  interestRatePerPeriod: 12.75
                  interestRateFrequencyType: 3
                  amortizationType: 1
                  interestType: 0
                  interestCalculationPeriodType: 1
                  transactionProcessingStrategyCode: advanced-payment-allocation-strategy
                  loanScheduleType: PROGRESSIVE
                  isInterestRecalculationEnabled: false
                  accountingRule: 1
                  charges:
                    - id: 12
                lmsConfig:
                  productClass: COVERED_CONSUMER
                  aprEnabled: true
                  aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                  aprTolerancePolicy: REGULAR
                  statementEnabled: true
                  statementLeadDays: 10
            example:
              fineract:
                name: Harbor 18-month personal loan
                shortName: HBR18
                currencyCode: USD
                principal: 8400
                numberOfRepayments: 18
                repaymentEvery: 1
                repaymentFrequencyType: 2
                interestRatePerPeriod: 12.75
                interestRateFrequencyType: 3
                amortizationType: 1
                interestType: 0
                interestCalculationPeriodType: 1
                transactionProcessingStrategyCode: advanced-payment-allocation-strategy
                loanScheduleType: PROGRESSIVE
                isInterestRecalculationEnabled: false
                accountingRule: 1
                charges:
                  - id: 12
              lmsConfig:
                productClass: COVERED_CONSUMER
                aprEnabled: true
                aprRounding: NEAREST_0_01_PERCENT_HALF_UP
                aprTolerancePolicy: REGULAR
                statementEnabled: true
                statementLeadDays: 10
  /v1/loans:
    post:
      tags:
        - Loans
      operationId: createLoanApplication
      summary: Create a loan application
      description: Creates a loan application for a customer against an active product; the clientId is the numeric value of
        the LendEasy customerId. Dates are parsed with the supplied dateFormat and locale. With
        command=calculateLoanSchedule the same body returns the computed amortization schedule — periods and totals —
        without persisting anything, which is how schedules are previewed before origination.
      x-permission: CREATE_LOAN
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: command
          in: query
          required: false
          description: Omit to create the application; calculateLoanSchedule returns a non-persisting schedule preview.
          schema:
            type: string
            enum:
              - calculateLoanSchedule
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 7204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - clientId
                - productId
                - loanType
                - principal
                - loanTermFrequency
                - loanTermFrequencyType
                - numberOfRepayments
                - repaymentEvery
                - repaymentFrequencyType
                - interestRatePerPeriod
                - interestType
                - interestCalculationPeriodType
                - amortizationType
                - transactionProcessingStrategyCode
                - expectedDisbursementDate
                - submittedOnDate
                - externalId
                - dateFormat
                - locale
                - charges
              properties:
                clientId:
                  type: integer
                productId:
                  type: integer
                loanType:
                  type: string
                principal:
                  type: integer
                loanTermFrequency:
                  type: integer
                loanTermFrequencyType:
                  type: integer
                numberOfRepayments:
                  type: integer
                repaymentEvery:
                  type: integer
                repaymentFrequencyType:
                  type: integer
                interestRatePerPeriod:
                  type: number
                interestType:
                  type: integer
                interestCalculationPeriodType:
                  type: integer
                amortizationType:
                  type: integer
                transactionProcessingStrategyCode:
                  type: string
                expectedDisbursementDate:
                  type: string
                  format: date
                submittedOnDate:
                  type: string
                  format: date
                externalId:
                  type: string
                  description: Caller-controlled identifier unique within the tenant and resource type.
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
                charges:
                  type: array
                  items:
                    type: object
                    required:
                      - chargeId
                      - amount
                    properties:
                      chargeId:
                        type: integer
                      amount:
                        type: integer
                        description: Decimal monetary amount encoded as a string.
              example:
                clientId: 412
                productId: 3
                loanType: individual
                principal: 8400
                loanTermFrequency: 18
                loanTermFrequencyType: 2
                numberOfRepayments: 18
                repaymentEvery: 1
                repaymentFrequencyType: 2
                interestRatePerPeriod: 13.25
                interestType: 0
                interestCalculationPeriodType: 1
                amortizationType: 1
                transactionProcessingStrategyCode: advanced-payment-allocation-strategy
                expectedDisbursementDate: 2026-08-12
                submittedOnDate: 2026-08-11
                externalId: origination-HBR-2026-001
                dateFormat: yyyy-MM-dd
                locale: en
                charges:
                  - chargeId: 12
                    amount: 252
            example:
              clientId: 412
              productId: 3
              loanType: individual
              principal: 8400
              loanTermFrequency: 18
              loanTermFrequencyType: 2
              numberOfRepayments: 18
              repaymentEvery: 1
              repaymentFrequencyType: 2
              interestRatePerPeriod: 13.25
              interestType: 0
              interestCalculationPeriodType: 1
              amortizationType: 1
              transactionProcessingStrategyCode: advanced-payment-allocation-strategy
              expectedDisbursementDate: 2026-08-12
              submittedOnDate: 2026-08-11
              externalId: origination-HBR-2026-001
              dateFormat: yyyy-MM-dd
              locale: en
              charges:
                - chargeId: 12
                  amount: 252
    get:
      tags:
        - Loans
      operationId: listLoans
      summary: List loans
      description: Lists loans with native offset paging. The envelope is totalFilteredRecords plus pageItems.
      x-permission: READ_LOAN
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: externalId
          in: query
          required: false
          description: Filter by external id.
          schema:
            type: string
        - name: accountNo
          in: query
          required: false
          description: Filter by loan account number.
          schema:
            type: string
        - name: clientId
          in: query
          required: false
          description: Filter by the customer’s numeric id.
          schema:
            type: integer
        - name: status
          in: query
          required: false
          description: Filter by loan status.
          schema:
            type: string
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            default: 200
        - name: orderBy
          in: query
          required: false
          description: Sort column.
          schema:
            type: string
        - name: sortOrder
          in: query
          required: false
          description: Sort direction.
          schema:
            type: string
            enum:
              - ASC
              - DESC
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - totalFilteredRecords
                  - pageItems
                properties:
                  totalFilteredRecords:
                    type: integer
                  pageItems:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - accountNo
                        - externalId
                        - status
                        - clientId
                        - clientName
                        - loanProductId
                        - loanProductName
                        - currency
                        - principal
                        - loanType
                        - timeline
                      properties:
                        id:
                          type: integer
                        accountNo:
                          type: string
                        externalId:
                          type: string
                          description: Caller-controlled identifier unique within the tenant and resource type.
                        status:
                          type: object
                          description: Current normalized lifecycle state.
                          required:
                            - id
                            - code
                            - value
                            - pendingApproval
                            - active
                          properties:
                            id:
                              type: integer
                            code:
                              type: string
                            value:
                              type: string
                            pendingApproval:
                              type: boolean
                            active:
                              type: boolean
                        clientId:
                          type: integer
                        clientName:
                          type: string
                        loanProductId:
                          type: integer
                        loanProductName:
                          type: string
                        currency:
                          type: object
                          description: ISO 4217 currency code.
                          required:
                            - code
                            - displaySymbol
                          properties:
                            code:
                              type: string
                            displaySymbol:
                              type: string
                        principal:
                          type: integer
                        loanType:
                          type: object
                          required:
                            - id
                            - code
                            - value
                          properties:
                            id:
                              type: integer
                            code:
                              type: string
                            value:
                              type: string
                        timeline:
                          type: object
                          required:
                            - submittedOnDate
                            - approvedOnDate
                            - actualDisbursementDate
                          properties:
                            submittedOnDate:
                              type: array
                              items:
                                type: integer
                            approvedOnDate:
                              type: array
                              items:
                                type: integer
                            actualDisbursementDate:
                              type: array
                              items:
                                type: integer
              example:
                totalFilteredRecords: 1
                pageItems:
                  - id: 7204
                    accountNo: "000007204"
                    externalId: origination-HBR-2026-001
                    status:
                      id: 300
                      code: loanStatusType.active
                      value: Active
                      pendingApproval: false
                      active: true
                    clientId: 412
                    clientName: Maya Chen
                    loanProductId: 3
                    loanProductName: Harbor 18-month personal loan
                    currency:
                      code: USD
                      displaySymbol: $
                    principal: 8400
                    loanType:
                      id: 1
                      code: loanType.individual
                      value: Individual
                    timeline:
                      submittedOnDate:
                        - 2026
                        - 8
                        - 11
                      approvedOnDate:
                        - 2026
                        - 8
                        - 11
                      actualDisbursementDate:
                        - 2026
                        - 8
                        - 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}:
    get:
      tags:
        - Loans
      operationId: getLoan
      summary: Retrieve a loan
      description: Returns the full loan model. The associations parameter selects embedded relations — repaymentSchedule,
        transactions, charges, or all — so the authoritative repayment schedule is read here rather than from a separate
        route; exclude and fields trim the response.
      x-permission: READ_LOAN
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: associations
          in: query
          required: false
          description: Comma-separated relations to embed, for example repaymentSchedule,transactions; defaults to all.
          schema:
            type: string
        - name: exclude
          in: query
          required: false
          description: Comma-separated associations to omit.
          schema:
            type: string
        - name: fields
          in: query
          required: false
          description: Comma-separated fields to include.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - accountNo
                  - externalId
                  - status
                  - clientId
                  - clientName
                  - loanProductId
                  - loanProductName
                  - currency
                  - principal
                  - loanType
                  - timeline
                  - approvedPrincipal
                  - annualInterestRate
                  - numberOfRepayments
                  - summary
                  - repaymentSchedule
                properties:
                  id:
                    type: integer
                  accountNo:
                    type: string
                  externalId:
                    type: string
                    description: Caller-controlled identifier unique within the tenant and resource type.
                  status:
                    type: object
                    description: Current normalized lifecycle state.
                    required:
                      - id
                      - code
                      - value
                      - pendingApproval
                      - active
                    properties:
                      id:
                        type: integer
                      code:
                        type: string
                      value:
                        type: string
                      pendingApproval:
                        type: boolean
                      active:
                        type: boolean
                  clientId:
                    type: integer
                  clientName:
                    type: string
                  loanProductId:
                    type: integer
                  loanProductName:
                    type: string
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                      - displaySymbol
                    properties:
                      code:
                        type: string
                      displaySymbol:
                        type: string
                  principal:
                    type: integer
                  loanType:
                    type: object
                    required:
                      - id
                      - code
                      - value
                    properties:
                      id:
                        type: integer
                      code:
                        type: string
                      value:
                        type: string
                  timeline:
                    type: object
                    required:
                      - submittedOnDate
                      - approvedOnDate
                      - actualDisbursementDate
                    properties:
                      submittedOnDate:
                        type: array
                        items:
                          type: integer
                      approvedOnDate:
                        type: array
                        items:
                          type: integer
                      actualDisbursementDate:
                        type: array
                        items:
                          type: integer
                  approvedPrincipal:
                    type: integer
                  annualInterestRate:
                    type: number
                  numberOfRepayments:
                    type: integer
                  summary:
                    type: object
                    required:
                      - currency
                      - principalDisbursed
                      - principalOutstanding
                      - interestCharged
                      - interestOutstanding
                      - feeChargesCharged
                      - totalOutstanding
                      - totalOverdue
                    properties:
                      currency:
                        type: object
                        description: ISO 4217 currency code.
                        required:
                          - code
                        properties:
                          code:
                            type: string
                      principalDisbursed:
                        type: integer
                      principalOutstanding:
                        type: number
                      interestCharged:
                        type: number
                      interestOutstanding:
                        type: number
                      feeChargesCharged:
                        type: integer
                      totalOutstanding:
                        type: number
                      totalOverdue:
                        type: integer
                  repaymentSchedule:
                    type: object
                    required:
                      - currency
                      - loanTermInDays
                      - totalPrincipalExpected
                      - periods
                    properties:
                      currency:
                        type: object
                        description: ISO 4217 currency code.
                        required:
                          - code
                        properties:
                          code:
                            type: string
                      loanTermInDays:
                        type: integer
                      totalPrincipalExpected:
                        type: integer
                      periods:
                        type: array
                        items:
                          type: object
                          required:
                            - period
                            - dueDate
                            - principalDue
                            - interestDue
                            - feeChargesDue
                            - totalDueForPeriod
                            - principalLoanBalanceOutstanding
                          properties:
                            period:
                              type: integer
                            dueDate:
                              type: array
                              items:
                                type: integer
                            principalDue:
                              type: number
                            interestDue:
                              type: number
                            feeChargesDue:
                              type: integer
                            totalDueForPeriod:
                              type: number
                            principalLoanBalanceOutstanding:
                              type: number
              example:
                id: 7204
                accountNo: "000007204"
                externalId: origination-HBR-2026-001
                status:
                  id: 300
                  code: loanStatusType.active
                  value: Active
                  pendingApproval: false
                  active: true
                clientId: 412
                clientName: Maya Chen
                loanProductId: 3
                loanProductName: Harbor 18-month personal loan
                currency:
                  code: USD
                  displaySymbol: $
                principal: 8400
                loanType:
                  id: 1
                  code: loanType.individual
                  value: Individual
                timeline:
                  submittedOnDate:
                    - 2026
                    - 8
                    - 11
                  approvedOnDate:
                    - 2026
                    - 8
                    - 11
                  actualDisbursementDate:
                    - 2026
                    - 8
                    - 12
                approvedPrincipal: 8400
                annualInterestRate: 13.25
                numberOfRepayments: 18
                summary:
                  currency:
                    code: USD
                  principalDisbursed: 8400
                  principalOutstanding: 7975.61
                  interestCharged: 1160.52
                  interestOutstanding: 88.06
                  feeChargesCharged: 252
                  totalOutstanding: 8063.67
                  totalOverdue: 0
                repaymentSchedule:
                  currency:
                    code: USD
                  loanTermInDays: 548
                  totalPrincipalExpected: 8400
                  periods:
                    - period: 1
                      dueDate:
                        - 2026
                        - 9
                        - 12
                      principalDue: 424.39
                      interestDue: 92.75
                      feeChargesDue: 0
                      totalDueForPeriod: 517.14
                      principalLoanBalanceOutstanding: 7975.61
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Loans
      operationId: updateLoanApplication
      summary: Update a submitted application
      description: Modifies a loan application while it is still submitted and pending approval, accepting the same field
        catalog as creation. With command=markAsFraud — a governed variant carrying a body of fraud true or false — the
        route instead toggles the loan’s fraud flag.
      x-permission: UPDATE_LOAN
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: command
          in: query
          required: false
          description: Omit to modify the submitted application; markAsFraud toggles the fraud flag.
          schema:
            type: string
            enum:
              - markAsFraud
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                  - changes
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - principal
                    properties:
                      principal:
                        type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 7204
                changes:
                  principal: 8400
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - principal
                - expectedDisbursementDate
                - dateFormat
                - locale
              properties:
                principal:
                  type: integer
                expectedDisbursementDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                principal: 8400
                expectedDisbursementDate: 2026-08-12
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              principal: 8400
              expectedDisbursementDate: 2026-08-12
              dateFormat: yyyy-MM-dd
              locale: en
    post:
      tags:
        - Loans
      operationId: transitionLoan
      summary: Approve, reject, withdraw, or terminate a loan
      description: "Executes a lifecycle command selected by the command parameter: approve (approvedOnDate, optional
        approvedLoanAmount and expectedDisbursementDate), reject (rejectedOnDate), withdrawnByApplicant
        (withdrawnOnDate), and the governed contractTermination and undoContractTermination. Governed commands require a
        LendEasy-Case header when case management is enabled, and maker-checker may park the command for a second
        approver. Disbursement has no public command — money moves through the funding API."
      x-permission: APPROVE_LOAN | REJECT_LOAN | WITHDRAW_LOAN | CONTRACT_TERMINATION_LOAN
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
            - actions:approve
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: Lifecycle command to execute.
          schema:
            type: string
            enum:
              - approve
              - reject
              - withdrawnByApplicant
              - contractTermination
              - undoContractTermination
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 7204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - approvedOnDate
                - approvedLoanAmount
                - expectedDisbursementDate
                - dateFormat
                - locale
              properties:
                approvedOnDate:
                  type: string
                  format: date
                approvedLoanAmount:
                  type: integer
                expectedDisbursementDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                approvedOnDate: 2026-08-11
                approvedLoanAmount: 8400
                expectedDisbursementDate: 2026-08-12
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              approvedOnDate: 2026-08-11
              approvedLoanAmount: 8400
              expectedDisbursementDate: 2026-08-12
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/loans/{loanId}/summary:
    get:
      tags:
        - Loans
      operationId: getLoanSummary
      summary: Retrieve a loan summary
      description: "Returns the servicing read model in one call: balances, overdue components, the payoff projection, the APR
        disclosure, the latest statement, in-flight payments, open action requests, autopay state, and active
        restrictions. The payoff block is computed for payoffGoodThroughDate — or the current business date when omitted
        — with no ledger effect; there is no separate payoff-quote or APR route."
      x-permission: READ_LMS_LOAN_SUMMARY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: payoffGoodThroughDate
          in: query
          required: false
          description: Good-through date for the payoff projection; defaults to the business date.
          schema:
            type: string
            format: date
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - loanRef
                  - customerRef
                  - status
                  - currency
                  - principalOutstanding
                  - overdue
                  - payoff
                  - aprDisclosure
                  - latestStatement
                  - inFlightPaymentAmount
                  - openActionRequests
                  - autopayState
                  - activeRestrictions
                  - fineractLinks
                  - asOf
                properties:
                  loanRef:
                    type: string
                  customerRef:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  principalOutstanding:
                    type: string
                  overdue:
                    type: object
                    required:
                      - totalOverdue
                      - principalOverdue
                      - interestOverdue
                      - feesOverdue
                      - penaltyOverdue
                    properties:
                      totalOverdue:
                        type: string
                      principalOverdue:
                        type: string
                      interestOverdue:
                        type: string
                      feesOverdue:
                        type: string
                      penaltyOverdue:
                        type: string
                  payoff:
                    type: object
                    required:
                      - available
                      - principal
                      - interestAccruedToDate
                      - fees
                      - penalties
                      - total
                      - currency
                      - goodThroughDate
                      - quotedAt
                      - validUntil
                    properties:
                      available:
                        type: boolean
                      principal:
                        type: string
                      interestAccruedToDate:
                        type: string
                        format: date
                      fees:
                        type: string
                      penalties:
                        type: string
                      total:
                        type: string
                      currency:
                        type: string
                        pattern: ^[A-Z]{3}$
                        description: ISO 4217 currency code.
                      goodThroughDate:
                        type: string
                        format: date
                      quotedAt:
                        type: string
                        format: date-time
                      validUntil:
                        type: string
                  aprDisclosure:
                    type: object
                    required:
                      - status
                      - method
                      - apr
                      - financeCharge
                      - amountFinanced
                      - totalOfPayments
                      - currency
                      - toleranceApplied
                      - finalizedAt
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      method:
                        type: string
                      apr:
                        type: string
                      financeCharge:
                        type: string
                      amountFinanced:
                        type: string
                      totalOfPayments:
                        type: string
                      currency:
                        type: string
                        pattern: ^[A-Z]{3}$
                        description: ISO 4217 currency code.
                      toleranceApplied:
                        type: string
                      finalizedAt:
                        type: string
                        format: date-time
                  latestStatement:
                    type: object
                    required:
                      - status
                      - statementId
                      - dueDate
                    properties:
                      status:
                        type: string
                        description: Current normalized lifecycle state.
                      statementId:
                        type: integer
                      dueDate:
                        type: string
                        format: date
                  inFlightPaymentAmount:
                    type: string
                  openActionRequests:
                    type: array
                    items:
                      type: object
                  autopayState:
                    type: string
                  activeRestrictions:
                    type: array
                    items:
                      type: object
                  fineractLinks:
                    type: object
                    required:
                      - loanId
                    properties:
                      loanId:
                        type: integer
                        description: Stable opaque loan identifier.
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
              example:
                loanRef: "7204"
                customerRef: "412"
                status: ACTIVE
                currency: USD
                principalOutstanding: "7975.61"
                overdue:
                  totalOverdue: "0.00"
                  principalOverdue: "0.00"
                  interestOverdue: "0.00"
                  feesOverdue: "0.00"
                  penaltyOverdue: "0.00"
                payoff:
                  available: true
                  principal: "7975.61"
                  interestAccruedToDate: "90.97"
                  fees: "0.00"
                  penalties: "0.00"
                  total: "8066.58"
                  currency: USD
                  goodThroughDate: 2026-10-01
                  quotedAt: 2026-09-20T10:00:00Z
                  validUntil: 2026-10-01
                aprDisclosure:
                  status: FINALIZED
                  method: REG_Z_ACTUARIAL_APPENDIX_J
                  apr: "17.29"
                  financeCharge: "1160.52"
                  amountFinanced: "8148.00"
                  totalOfPayments: "9308.52"
                  currency: USD
                  toleranceApplied: REGULAR
                  finalizedAt: 2026-08-11T18:00:05Z
                latestStatement:
                  status: AVAILABLE
                  statementId: 7719
                  dueDate: 2026-10-12
                inFlightPaymentAmount: "0.00"
                openActionRequests: []
                autopayState: ACTIVE
                activeRestrictions: []
                fineractLinks:
                  loanId: 7204
                asOf: 2026-09-20T10:00:00Z
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/transactions:
    post:
      tags:
        - Servicing actions
      operationId: executeLoanTransactionCommand
      summary: Execute a governed transaction command
      description: Executes one of 19 governed transaction commands selected by the command parameter — interest waivers,
        write-off and charge-off with their undos, close, foreclosure, refunds and credits, recovery payment, re-age,
        and re-amortize. Human servicing calls require a LendEasy-Case header naming an open case for this borrower when
        case management is enabled; each execution writes a governance record and maker-checker may park the command for
        a second approver. Repayments and disbursements are not accepted here — money moves through the payment and
        funding APIs.
      x-permission: Per command (native permission, maker-checker configurable)
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: Governed transaction command to execute.
          schema:
            type: string
            enum:
              - waiveinterest
              - interestPaymentWaiver
              - writeoff
              - undowriteoff
              - charge-off
              - undo-charge-off
              - close
              - foreclosure
              - goodwillCredit
              - merchantIssuedRefund
              - payoutRefund
              - chargeRefund
              - creditBalanceRefund
              - refundByCash
              - recoverypayment
              - reAge
              - undoReAge
              - reAmortize
              - undoReAmortize
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                  - changes
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - transactionDate
                      - transactionAmount
                    properties:
                      transactionDate:
                        type: string
                        format: date
                      transactionAmount:
                        type: number
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 30514
                changes:
                  transactionDate: 2027-08-20
                  transactionAmount: 92.75
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - transactionDate
                - transactionAmount
                - note
                - dateFormat
                - locale
              properties:
                transactionDate:
                  type: string
                  format: date
                transactionAmount:
                  type: number
                note:
                  type: string
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                transactionDate: 2027-08-20
                transactionAmount: 92.75
                note: Hardship interest waiver per case plan.
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              transactionDate: 2027-08-20
              transactionAmount: 92.75
              note: Hardship interest waiver per case plan.
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/loans/{loanId}/transactions/template:
    get:
      tags:
        - Servicing actions
      operationId: getLoanTransactionTemplate
      summary: Retrieve a transaction template
      description: Returns the prefilled amounts and option catalogs for a prospective transaction; command selects the
        disburse or repayment template used by operator interfaces.
      x-permission: READ_LOANTRANSACTION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: command
          in: query
          required: false
          description: Template variant.
          schema:
            type: string
            enum:
              - disburse
              - repayment
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - transactionType
                  - date
                  - currency
                  - amount
                  - paymentTypeOptions
                properties:
                  transactionType:
                    type: object
                    required:
                      - id
                      - code
                      - value
                    properties:
                      id:
                        type: integer
                      code:
                        type: string
                      value:
                        type: string
                  date:
                    type: array
                    items:
                      type: integer
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  amount:
                    type: number
                    description: Decimal monetary amount encoded as a string.
                  paymentTypeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
              example:
                transactionType:
                  id: 2
                  code: loanTransactionType.repayment
                  value: Repayment
                date:
                  - 2026
                  - 9
                  - 12
                currency:
                  code: USD
                amount: 517.14
                paymentTypeOptions:
                  - id: 1
                    name: ACH
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/transactions/{transactionId}:
    get:
      tags:
        - Servicing actions
      operationId: getLoanTransaction
      summary: Retrieve a loan transaction
      description: Returns one ledger transaction with its type, amounts, allocation components, and reversal state.
      x-permission: READ_LOANTRANSACTION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: transactionId
          in: path
          required: true
          description: Stable opaque transaction identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - type
                  - date
                  - currency
                  - amount
                  - principalPortion
                  - interestPortion
                  - feeChargesPortion
                  - penaltyChargesPortion
                  - outstandingLoanBalance
                  - manuallyReversed
                properties:
                  id:
                    type: integer
                  type:
                    type: object
                    required:
                      - id
                      - code
                      - value
                    properties:
                      id:
                        type: integer
                      code:
                        type: string
                      value:
                        type: string
                  date:
                    type: array
                    items:
                      type: integer
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  amount:
                    type: number
                    description: Decimal monetary amount encoded as a string.
                  principalPortion:
                    type: number
                  interestPortion:
                    type: number
                  feeChargesPortion:
                    type: integer
                  penaltyChargesPortion:
                    type: integer
                  outstandingLoanBalance:
                    type: number
                  manuallyReversed:
                    type: boolean
              example:
                id: 30411
                type:
                  id: 2
                  code: loanTransactionType.repayment
                  value: Repayment
                date:
                  - 2026
                  - 9
                  - 12
                currency:
                  code: USD
                amount: 517.14
                principalPortion: 424.39
                interestPortion: 92.75
                feeChargesPortion: 0
                penaltyChargesPortion: 0
                outstandingLoanBalance: 7975.61
                manuallyReversed: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/interest-pauses:
    get:
      tags:
        - Servicing actions
      operationId: listInterestPauses
      summary: List interest pauses
      description: Returns the loan’s interest-pause periods.
      x-permission: READ_INTEREST_PAUSE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - startDate
                    - endDate
                  properties:
                    id:
                      type: integer
                    startDate:
                      type: string
                      format: date
                    endDate:
                      type: string
                      format: date
              example:
                - id: 12
                  startDate: 2027-08-01
                  endDate: 2027-10-31
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Servicing actions
      operationId: createInterestPause
      summary: Pause interest accrual
      description: Creates a governed interest-free period between two dates, typically as hardship relief. Requires a
        LendEasy-Case header for human servicing calls when case management is enabled.
      x-permission: CREATE_INTEREST_PAUSE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - startDate
                - endDate
                - dateFormat
                - locale
              properties:
                startDate:
                  type: string
                  format: date
                endDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                startDate: 2027-08-01
                endDate: 2027-10-31
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              startDate: 2027-08-01
              endDate: 2027-10-31
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/loans/{loanId}/interest-pauses/{variationId}:
    put:
      tags:
        - Servicing actions
      operationId: updateInterestPause
      summary: Update an interest pause
      description: Adjusts the dates of an interest-pause period.
      x-permission: UPDATE_INTEREST_PAUSE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: variationId
          in: path
          required: true
          description: Stable opaque variation identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - changes
                properties:
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - endDate
                    properties:
                      endDate:
                        type: string
                        format: date
              example:
                resourceId: 12
                changes:
                  endDate: 2027-11-30
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - startDate
                - endDate
                - dateFormat
                - locale
              properties:
                startDate:
                  type: string
                  format: date
                endDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                startDate: 2027-08-01
                endDate: 2027-11-30
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              startDate: 2027-08-01
              endDate: 2027-11-30
              dateFormat: yyyy-MM-dd
              locale: en
    delete:
      tags:
        - Servicing actions
      operationId: deleteInterestPause
      summary: Remove an interest pause
      description: Removes an interest-pause period with no request body.
      x-permission: DELETE_INTEREST_PAUSE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: variationId
          in: path
          required: true
          description: Stable opaque variation identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                properties:
                  resourceId:
                    type: integer
              example:
                resourceId: 12
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/rescheduleloans:
    get:
      tags:
        - Servicing actions
      operationId: listLoanReschedules
      summary: List reschedule requests
      description: Lists loan reschedule requests and their approval state.
      x-permission: READ_RESCHEDULELOAN
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - loanId
                    - rescheduleFromDate
                    - rescheduleReasonCodeValue
                    - statusEnum
                  properties:
                    id:
                      type: integer
                    loanId:
                      type: integer
                      description: Stable opaque loan identifier.
                    rescheduleFromDate:
                      type: array
                      items:
                        type: integer
                    rescheduleReasonCodeValue:
                      type: object
                      required:
                        - id
                        - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                    statusEnum:
                      type: object
                      required:
                        - id
                        - code
                        - value
                      properties:
                        id:
                          type: integer
                        code:
                          type: string
                        value:
                          type: string
              example:
                - id: 5
                  loanId: 7204
                  rescheduleFromDate:
                    - 2027
                    - 9
                    - 1
                  rescheduleReasonCodeValue:
                    id: 61
                    name: Hardship
                  statusEnum:
                    id: 100
                    code: loanStatusType.submitted.and.pending.approval
                    value: Submitted and pending approval
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Servicing actions
      operationId: createLoanReschedule
      summary: Request a reschedule
      description: Creates a governed reschedule request — grace periods, extra terms, a new interest rate, an adjusted due
        date, or a recurring moratorium — effective from rescheduleFromDate. The request does not change the schedule
        until a different user approves it.
      x-permission: CREATE_RESCHEDULELOAN
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - loanId
                properties:
                  resourceId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
              example:
                resourceId: 5
                loanId: 7204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - loanId
                - rescheduleFromDate
                - rescheduleReasonId
                - submittedOnDate
                - graceOnPrincipal
                - recalculateInterest
                - rescheduleReasonComment
                - dateFormat
                - locale
              properties:
                loanId:
                  type: integer
                  description: Stable opaque loan identifier.
                rescheduleFromDate:
                  type: string
                  format: date
                rescheduleReasonId:
                  type: integer
                submittedOnDate:
                  type: string
                  format: date
                graceOnPrincipal:
                  type: integer
                recalculateInterest:
                  type: boolean
                rescheduleReasonComment:
                  type: string
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                loanId: 7204
                rescheduleFromDate: 2027-09-01
                rescheduleReasonId: 61
                submittedOnDate: 2027-08-20
                graceOnPrincipal: 2
                recalculateInterest: true
                rescheduleReasonComment: Temporary income reduction.
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              loanId: 7204
              rescheduleFromDate: 2027-09-01
              rescheduleReasonId: 61
              submittedOnDate: 2027-08-20
              graceOnPrincipal: 2
              recalculateInterest: true
              rescheduleReasonComment: Temporary income reduction.
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/rescheduleloans/template:
    get:
      tags:
        - Servicing actions
      operationId: getLoanRescheduleTemplate
      summary: Retrieve the reschedule template
      description: Returns the reason-code catalog for creating a reschedule request.
      x-permission: READ_RESCHEDULELOAN
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - rescheduleReasons
                properties:
                  rescheduleReasons:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - name
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
              example:
                rescheduleReasons:
                  - id: 61
                    name: Hardship
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/rescheduleloans/{scheduleId}:
    get:
      tags:
        - Servicing actions
      operationId: getLoanReschedule
      summary: Retrieve a reschedule request
      description: Returns one reschedule request with its proposed changes and decision state.
      x-permission: READ_RESCHEDULELOAN
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: scheduleId
          in: path
          required: true
          description: Stable opaque schedule identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - loanId
                  - rescheduleFromDate
                  - rescheduleReasonComment
                  - statusEnum
                properties:
                  id:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  rescheduleFromDate:
                    type: array
                    items:
                      type: integer
                  rescheduleReasonComment:
                    type: string
                  statusEnum:
                    type: object
                    required:
                      - id
                      - code
                      - value
                    properties:
                      id:
                        type: integer
                      code:
                        type: string
                      value:
                        type: string
              example:
                id: 5
                loanId: 7204
                rescheduleFromDate:
                  - 2027
                  - 9
                  - 1
                rescheduleReasonComment: Temporary income reduction.
                statusEnum:
                  id: 200
                  code: loanStatusType.approved
                  value: Approved
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Servicing actions
      operationId: decideLoanReschedule
      summary: Approve or reject a reschedule
      description: Approves or rejects a pending reschedule request. Approval is the second-person control — the approver must
        differ from the requester — and applies the schedule change; it retains the originating governance linkage and
        takes no new LendEasy-Case header.
      x-permission: APPROVE_RESCHEDULELOAN | REJECT_RESCHEDULELOAN
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
            - actions:approve
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: scheduleId
          in: path
          required: true
          description: Stable opaque schedule identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: Decision to record.
          schema:
            type: string
            enum:
              - approve
              - reject
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - resourceId
                  - loanId
                properties:
                  resourceId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
              example:
                resourceId: 5
                loanId: 7204
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - approvedOnDate
                - dateFormat
                - locale
              properties:
                approvedOnDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                approvedOnDate: 2027-08-21
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              approvedOnDate: 2027-08-21
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/makercheckers:
    get:
      tags:
        - Servicing actions
      operationId: listPendingCommands
      summary: List commands awaiting approval
      description: "Returns the checker inbox: governed commands parked by maker-checker and awaiting a second approver."
      x-permission: READ_MAKERCHECKER
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - actionName
                    - entityName
                    - resourceId
                    - maker
                    - madeOnDate
                    - commandAsJson
                  properties:
                    id:
                      type: integer
                    actionName:
                      type: string
                    entityName:
                      type: string
                    resourceId:
                      type: integer
                    maker:
                      type: string
                    madeOnDate:
                      type: string
                      format: date
                    commandAsJson:
                      type: string
              example:
                - id: 118
                  actionName: WRITEOFF
                  entityName: LOAN
                  resourceId: 7204
                  maker: ana.alvarez
                  madeOnDate: 2027-08-20T17:14:09Z
                  commandAsJson: '{"transactionDate":"2027-08-20"}'
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/makercheckers/{auditId}:
    post:
      tags:
        - Servicing actions
      operationId: decidePendingCommand
      summary: Approve or reject a parked command
      description: Completes maker-checker for one parked command. The decider must be a different user holding the command’s
        checker permission; approval executes the original command and completes its governance record.
      x-permission: Per command checker permission
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: auditId
          in: path
          required: true
          description: Stable opaque audit identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: Decision to record.
          schema:
            type: string
            enum:
              - approve
              - reject
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - auditId
                  - resourceId
                properties:
                  auditId:
                    type: integer
                  resourceId:
                    type: integer
              example:
                auditId: 118
                resourceId: 30514
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
  /v1/loans/{loanId}/charges:
    get:
      tags:
        - Charges
      operationId: listLoanCharges
      summary: List loan charges
      description: Lists charges applied to the loan with assessed, paid, waived, and outstanding amounts.
      x-permission: READ_LOANCHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - chargeId
                    - name
                    - chargeTimeType
                    - currency
                    - amount
                    - amountPaid
                    - amountWaived
                    - amountOutstanding
                    - dueDate
                    - penalty
                    - paid
                    - waived
                  properties:
                    id:
                      type: integer
                    chargeId:
                      type: integer
                    name:
                      type: string
                    chargeTimeType:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                    currency:
                      type: object
                      description: ISO 4217 currency code.
                      required:
                        - code
                      properties:
                        code:
                          type: string
                    amount:
                      type: integer
                      description: Decimal monetary amount encoded as a string.
                    amountPaid:
                      type: integer
                    amountWaived:
                      type: integer
                    amountOutstanding:
                      type: integer
                    dueDate:
                      type: array
                      items:
                        type: integer
                    penalty:
                      type: boolean
                    paid:
                      type: boolean
                    waived:
                      type: boolean
              example:
                - id: 44
                  chargeId: 21
                  name: Late fee
                  chargeTimeType:
                    id: 9
                    value: Overdue Installment Fee
                  currency:
                    code: USD
                  amount: 18
                  amountPaid: 0
                  amountWaived: 0
                  amountOutstanding: 18
                  dueDate:
                    - 2027
                    - 4
                    - 10
                  penalty: true
                  paid: false
                  waived: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Charges
      operationId: addLoanCharge
      summary: Add a loan charge
      description: Applies a configured charge definition to the loan — a governed command requiring a LendEasy-Case header
        for human servicing calls when case management is enabled. Automated fees such as returned-payment fees are
        assessed by the system, not through this route.
      x-permission: CREATE_LOANCHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 44
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - chargeId
                - amount
                - dueDate
                - dateFormat
                - locale
              properties:
                chargeId:
                  type: integer
                amount:
                  type: integer
                  description: Decimal monetary amount encoded as a string.
                dueDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                chargeId: 21
                amount: 18
                dueDate: 2027-04-10
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              chargeId: 21
              amount: 18
              dueDate: 2027-04-10
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/loans/{loanId}/charges/template:
    get:
      tags:
        - Charges
      operationId: getLoanChargeTemplate
      summary: Retrieve the loan-charge template
      description: Returns the applicable charge options for adding a charge to this loan.
      x-permission: READ_LOANCHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - chargeOptions
                properties:
                  chargeOptions:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - name
                        - penalty
                      properties:
                        id:
                          type: integer
                        name:
                          type: string
                        penalty:
                          type: boolean
              example:
                chargeOptions:
                  - id: 21
                    name: Late fee
                    penalty: true
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/loans/{loanId}/charges/{loanChargeId}:
    get:
      tags:
        - Charges
      operationId: getLoanCharge
      summary: Retrieve a loan charge
      description: Returns one applied charge with its amounts and lifecycle flags.
      x-permission: READ_LOANCHARGE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: loanChargeId
          in: path
          required: true
          description: Stable opaque loanCharge identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - chargeId
                  - name
                  - chargeTimeType
                  - currency
                  - amount
                  - amountPaid
                  - amountWaived
                  - amountOutstanding
                  - dueDate
                  - penalty
                  - paid
                  - waived
                properties:
                  id:
                    type: integer
                  chargeId:
                    type: integer
                  name:
                    type: string
                  chargeTimeType:
                    type: object
                    required:
                      - id
                      - value
                    properties:
                      id:
                        type: integer
                      value:
                        type: string
                  currency:
                    type: object
                    description: ISO 4217 currency code.
                    required:
                      - code
                    properties:
                      code:
                        type: string
                  amount:
                    type: integer
                    description: Decimal monetary amount encoded as a string.
                  amountPaid:
                    type: integer
                  amountWaived:
                    type: integer
                  amountOutstanding:
                    type: integer
                  dueDate:
                    type: array
                    items:
                      type: integer
                  penalty:
                    type: boolean
                  paid:
                    type: boolean
                  waived:
                    type: boolean
              example:
                id: 44
                chargeId: 21
                name: Late fee
                chargeTimeType:
                  id: 9
                  value: Overdue Installment Fee
                currency:
                  code: USD
                amount: 18
                amountPaid: 0
                amountWaived: 0
                amountOutstanding: 18
                dueDate:
                  - 2027
                  - 4
                  - 10
                penalty: true
                paid: false
                waived: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Charges
      operationId: updateLoanCharge
      summary: Update a loan charge
      description: Updates the amount or due date of an applied charge before financial dependencies exist — a governed command.
      x-permission: UPDATE_LOANCHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: loanChargeId
          in: path
          required: true
          description: Stable opaque loanCharge identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                  - changes
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - amount
                    properties:
                      amount:
                        type: integer
                        description: Decimal monetary amount encoded as a string.
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 44
                changes:
                  amount: 20
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - dueDate
                - dateFormat
                - locale
              properties:
                amount:
                  type: integer
                  description: Decimal monetary amount encoded as a string.
                dueDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                amount: 20
                dueDate: 2027-04-11
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              amount: 20
              dueDate: 2027-04-11
              dateFormat: yyyy-MM-dd
              locale: en
    delete:
      tags:
        - Charges
      operationId: removeLoanCharge
      summary: Remove a loan charge
      description: Removes an unapplied charge from the loan with no request body — a governed command. Assessed charges are
        waived or adjusted instead.
      x-permission: DELETE_LOANCHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: loanChargeId
          in: path
          required: true
          description: Stable opaque loanCharge identifier.
          schema:
            type: string
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 44
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
    post:
      tags:
        - Charges
      operationId: executeLoanChargeCommand
      summary: Waive or adjust a loan charge
      description: "Executes a governed charge command selected by the command parameter: waive forgives the outstanding
        amount, and adjustment corrects an assessed amount with a transaction date. Requires a LendEasy-Case header for
        human servicing calls when case management is enabled."
      x-permission: WAIVE_LOANCHARGE | ADJUSTMENT_LOANCHARGE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: loanId
          in: path
          required: true
          description: Stable opaque loan identifier.
          schema:
            type: string
        - name: loanChargeId
          in: path
          required: true
          description: Stable opaque loanCharge identifier.
          schema:
            type: string
        - name: command
          in: query
          required: true
          description: Charge command to execute.
          schema:
            type: string
            enum:
              - waive
              - adjustment
        - name: LendEasy-Case
          in: header
          required: false
          description: Open servicing-case reference for this borrower. Required on human servicing mutations when case management
            is enabled; automation never sends it.
          schema:
            type: string
            minLength: 1
            maxLength: 100
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - clientId
                  - loanId
                  - resourceId
                  - changes
                properties:
                  officeId:
                    type: integer
                  clientId:
                    type: integer
                  loanId:
                    type: integer
                    description: Stable opaque loan identifier.
                  resourceId:
                    type: integer
                  changes:
                    type: object
                    required:
                      - amountWaived
                    properties:
                      amountWaived:
                        type: integer
              example:
                officeId: 1
                clientId: 412
                loanId: 7204
                resourceId: 44
                changes:
                  amountWaived: 18
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - transactionDate
                - dateFormat
                - locale
              properties:
                amount:
                  type: integer
                  description: Decimal monetary amount encoded as a string.
                transactionDate:
                  type: string
                  format: date
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                amount: 18
                transactionDate: 2027-04-15
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              amount: 18
              transactionDate: 2027-04-15
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/journalentries:
    get:
      tags:
        - Accounting
      operationId: listJournalEntries
      summary: List journal entries
      description: Lists balanced ledger entries by account, office, loan, transaction, date range, and manual-entry flag,
        using the native totalFilteredRecords envelope.
      x-permission: READ_JOURNALENTRY
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: glAccountId
          in: query
          required: false
          description: Filter by ledger account.
          schema:
            type: integer
        - name: loanId
          in: query
          required: false
          description: Filter by loan.
          schema:
            type: integer
        - name: transactionId
          in: query
          required: false
          description: Filter by source transaction.
          schema:
            type: string
        - name: entityType
          in: query
          required: false
          description: Filter by source entity type.
          schema:
            type: integer
        - name: manualEntriesOnly
          in: query
          required: false
          description: Restrict to manual entries.
          schema:
            type: boolean
        - name: fromDate
          in: query
          required: false
          description: Inclusive transaction-date lower bound.
          schema:
            type: string
            format: date
        - name: toDate
          in: query
          required: false
          description: Inclusive transaction-date upper bound.
          schema:
            type: string
            format: date
        - name: offset
          in: query
          required: false
          description: Zero-based offset into the result set.
          schema:
            type: integer
            minimum: 0
            default: 0
        - name: limit
          in: query
          required: false
          description: Maximum records to return.
          schema:
            type: integer
            minimum: 1
            default: 200
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - totalFilteredRecords
                  - pageItems
                properties:
                  totalFilteredRecords:
                    type: integer
                  pageItems:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - officeId
                        - officeName
                        - glAccountId
                        - glAccountName
                        - glAccountCode
                        - glAccountType
                        - transactionDate
                        - entryType
                        - amount
                        - transactionId
                        - entityType
                        - entityId
                        - currency
                        - submittedOnDate
                      properties:
                        id:
                          type: integer
                        officeId:
                          type: integer
                        officeName:
                          type: string
                        glAccountId:
                          type: integer
                        glAccountName:
                          type: string
                        glAccountCode:
                          type: string
                        glAccountType:
                          type: object
                          required:
                            - id
                            - value
                          properties:
                            id:
                              type: integer
                            value:
                              type: string
                        transactionDate:
                          type: array
                          items:
                            type: integer
                        entryType:
                          type: object
                          required:
                            - id
                            - value
                          properties:
                            id:
                              type: integer
                            value:
                              type: string
                        amount:
                          type: number
                          description: Decimal monetary amount encoded as a string.
                        transactionId:
                          type: string
                        entityType:
                          type: object
                          required:
                            - id
                            - value
                          properties:
                            id:
                              type: integer
                            value:
                              type: string
                        entityId:
                          type: integer
                        currency:
                          type: object
                          description: ISO 4217 currency code.
                          required:
                            - code
                          properties:
                            code:
                              type: string
                        submittedOnDate:
                          type: array
                          items:
                            type: integer
              example:
                totalFilteredRecords: 1
                pageItems:
                  - id: 90211
                    officeId: 1
                    officeName: Head Office
                    glAccountId: 14
                    glAccountName: Interest income
                    glAccountCode: "4100"
                    glAccountType:
                      id: 4
                      value: INCOME
                    transactionDate:
                      - 2026
                      - 9
                      - 12
                    entryType:
                      id: 2
                      value: CREDIT
                    amount: 92.75
                    transactionId: L30411
                    entityType:
                      id: 1
                      value: LOAN
                    entityId: 7204
                    currency:
                      code: USD
                    submittedOnDate:
                      - 2026
                      - 9
                      - 15
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    post:
      tags:
        - Accounting
      operationId: createJournalEntry
      summary: Create a manual journal entry
      description: Posts a balanced manual journal entry with matching debit and credit lines. This route is restricted to
        accounting administrators; loan-servicing money movement never posts manual entries.
      x-permission: CREATE_JOURNALENTRY
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - officeId
                  - transactionId
                properties:
                  officeId:
                    type: integer
                  transactionId:
                    type: string
              example:
                officeId: 1
                transactionId: M90310
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - officeId
                - transactionDate
                - currencyCode
                - comments
                - debits
                - credits
                - dateFormat
                - locale
              properties:
                officeId:
                  type: integer
                transactionDate:
                  type: string
                  format: date
                currencyCode:
                  type: string
                comments:
                  type: string
                debits:
                  type: array
                  items:
                    type: object
                    required:
                      - glAccountId
                      - amount
                    properties:
                      glAccountId:
                        type: integer
                      amount:
                        type: integer
                        description: Decimal monetary amount encoded as a string.
                credits:
                  type: array
                  items:
                    type: object
                    required:
                      - glAccountId
                      - amount
                    properties:
                      glAccountId:
                        type: integer
                      amount:
                        type: integer
                        description: Decimal monetary amount encoded as a string.
                dateFormat:
                  type: string
                  format: date-time
                locale:
                  type: string
              example:
                officeId: 1
                transactionDate: 2026-09-30
                currencyCode: USD
                comments: Monthly accrual adjustment.
                debits:
                  - glAccountId: 22
                    amount: 120
                credits:
                  - glAccountId: 14
                    amount: 120
                dateFormat: yyyy-MM-dd
                locale: en
            example:
              officeId: 1
              transactionDate: 2026-09-30
              currencyCode: USD
              comments: Monthly accrual adjustment.
              debits:
                - glAccountId: 22
                  amount: 120
              credits:
                - glAccountId: 14
                  amount: 120
              dateFormat: yyyy-MM-dd
              locale: en
  /v1/glaccounts:
    get:
      tags:
        - Accounting
      operationId: listGlAccounts
      summary: List ledger accounts
      description: Returns the chart of accounts with type, usage, and activation.
      x-permission: READ_GLACCOUNT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - name
                    - glCode
                    - type
                    - usage
                    - manualEntriesAllowed
                    - disabled
                  properties:
                    id:
                      type: integer
                    name:
                      type: string
                    glCode:
                      type: string
                    type:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                    usage:
                      type: object
                      required:
                        - id
                        - value
                      properties:
                        id:
                          type: integer
                        value:
                          type: string
                    manualEntriesAllowed:
                      type: boolean
                    disabled:
                      type: boolean
              example:
                - id: 14
                  name: Interest income
                  glCode: "4100"
                  type:
                    id: 4
                    value: INCOME
                  usage:
                    id: 1
                    value: DETAIL
                  manualEntriesAllowed: true
                  disabled: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/glaccounts/{id}:
    get:
      tags:
        - Accounting
      operationId: getGlAccount
      summary: Retrieve a ledger account
      description: Returns one ledger account.
      x-permission: READ_GLACCOUNT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: id
          in: path
          required: true
          description: Stable opaque id identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - name
                  - glCode
                  - type
                  - usage
                  - manualEntriesAllowed
                  - disabled
                properties:
                  id:
                    type: integer
                  name:
                    type: string
                  glCode:
                    type: string
                  type:
                    type: object
                    required:
                      - id
                      - value
                    properties:
                      id:
                        type: integer
                      value:
                        type: string
                  usage:
                    type: object
                    required:
                      - id
                      - value
                    properties:
                      id:
                        type: integer
                      value:
                        type: string
                  manualEntriesAllowed:
                    type: boolean
                  disabled:
                    type: boolean
              example:
                id: 14
                name: Interest income
                glCode: "4100"
                type:
                  id: 4
                  value: INCOME
                usage:
                  id: 1
                  value: DETAIL
                manualEntriesAllowed: true
                disabled: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/reports:
    get:
      tags:
        - Reporting
      operationId: listReports
      summary: List report definitions
      description: Returns the operational report catalog with each report’s parameters. This surface is definition metadata;
        report execution and downloads are operator-side and are not part of the public API.
      x-permission: READ_REPORT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: array
                items:
                  type: object
                  required:
                    - id
                    - reportName
                    - reportType
                    - reportCategory
                    - useReport
                    - reportParameters
                  properties:
                    id:
                      type: integer
                    reportName:
                      type: string
                    reportType:
                      type: string
                    reportCategory:
                      type: string
                    useReport:
                      type: boolean
                    reportParameters:
                      type: array
                      items:
                        type: object
                        required:
                          - id
                          - parameterName
                        properties:
                          id:
                            type: integer
                          parameterName:
                            type: string
              example:
                - id: 81
                  reportName: Credit balance accounts
                  reportType: Table
                  reportCategory: Loan
                  useReport: true
                  reportParameters:
                    - id: 1
                      parameterName: asOfDate
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/reports/{id}:
    get:
      tags:
        - Reporting
      operationId: getReport
      summary: Retrieve a report definition
      description: Returns one report definition and its parameters.
      x-permission: READ_REPORT
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: id
          in: path
          required: true
          description: Stable opaque id identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - id
                  - reportName
                  - reportType
                  - reportCategory
                  - useReport
                  - reportParameters
                properties:
                  id:
                    type: integer
                  reportName:
                    type: string
                  reportType:
                    type: string
                  reportCategory:
                    type: string
                  useReport:
                    type: boolean
                  reportParameters:
                    type: array
                    items:
                      type: object
                      required:
                        - id
                        - parameterName
                      properties:
                        id:
                          type: integer
                        parameterName:
                          type: string
              example:
                id: 81
                reportName: Credit balance accounts
                reportType: Table
                reportCategory: Loan
                useReport: true
                reportParameters:
                  - id: 1
                    parameterName: asOfDate
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances:
    post:
      tags:
        - Merchant advances
      operationId: createMerchantAdvance
      summary: Create a merchant advance
      description: Creates a receivables-purchase application with explicit purchase price, purchased amount, sales
        remittance, and reporting terms.
      x-permission: CREATE_MERCHANT_ADVANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - externalId
                  - merchantId
                  - productId
                  - status
                  - currency
                  - purchasePrice
                  - purchasedAmount
                  - remainingPurchasedAmount
                  - remittanceRate
                  - projectedCompletionDate
                  - version
                properties:
                  advanceId:
                    type: string
                  externalId:
                    type: string
                    description: Caller-controlled identifier unique within the tenant and resource type.
                  merchantId:
                    type: string
                  productId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  purchasePrice:
                    type: string
                  purchasedAmount:
                    type: string
                  remainingPurchasedAmount:
                    type: string
                  remittanceRate:
                    type: string
                  projectedCompletionDate:
                    type: string
                    format: date
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                externalId: northstar-advance-2026
                merchantId: party_NORTHSTAR_4
                productId: prod_MERCHANT_ADVANCE_1
                status: submitted
                currency: USD
                purchasePrice: "48000.00"
                purchasedAmount: "60000.00"
                remainingPurchasedAmount: "60000.00"
                remittanceRate: "0.12"
                projectedCompletionDate: 2027-07-04
                version: 1
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - merchantId
                - productId
                - externalId
                - terms
              properties:
                merchantId:
                  type: string
                productId:
                  type: string
                externalId:
                  type: string
                  description: Caller-controlled identifier unique within the tenant and resource type.
                terms:
                  type: object
                  required:
                    - purchasePrice
                    - purchasedAmount
                    - currency
                    - remittanceRate
                    - reportingFrequency
                    - expectedMonthlySales
                  properties:
                    purchasePrice:
                      type: string
                    purchasedAmount:
                      type: string
                    currency:
                      type: string
                      pattern: ^[A-Z]{3}$
                      description: ISO 4217 currency code.
                    remittanceRate:
                      type: string
                    reportingFrequency:
                      type: string
                    expectedMonthlySales:
                      type: string
              example:
                merchantId: party_NORTHSTAR_4
                productId: prod_MERCHANT_ADVANCE_1
                externalId: northstar-advance-2026
                terms:
                  purchasePrice: "48000.00"
                  purchasedAmount: "60000.00"
                  currency: USD
                  remittanceRate: "0.12"
                  reportingFrequency: daily
                  expectedMonthlySales: "50000.00"
            example:
              merchantId: party_NORTHSTAR_4
              productId: prod_MERCHANT_ADVANCE_1
              externalId: northstar-advance-2026
              terms:
                purchasePrice: "48000.00"
                purchasedAmount: "60000.00"
                currency: USD
                remittanceRate: "0.12"
                reportingFrequency: daily
                expectedMonthlySales: "50000.00"
    get:
      tags:
        - Merchant advances
      operationId: listMerchantAdvances
      summary: List merchant advances
      description: Lists advances by merchant, product, state, breach status, and reporting freshness.
      x-permission: READ_MERCHANT_ADVANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
        - name: merchantId
          in: query
          schema:
            type: string
          description: Filter by external-party merchant ID.
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - advanceId
                        - externalId
                        - merchantId
                        - productId
                        - status
                        - currency
                        - purchasePrice
                        - purchasedAmount
                        - remainingPurchasedAmount
                        - remittanceRate
                        - projectedCompletionDate
                        - version
                      properties:
                        advanceId:
                          type: string
                        externalId:
                          type: string
                          description: Caller-controlled identifier unique within the tenant and resource type.
                        merchantId:
                          type: string
                        productId:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        purchasePrice:
                          type: string
                        purchasedAmount:
                          type: string
                        remainingPurchasedAmount:
                          type: string
                        remittanceRate:
                          type: string
                        projectedCompletionDate:
                          type: string
                          format: date
                        version:
                          type: integer
                          description: Monotonically increasing resource version.
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - advanceId: ma_northstar_6N8Q
                    externalId: northstar-advance-2026
                    merchantId: party_NORTHSTAR_4
                    productId: prod_MERCHANT_ADVANCE_1
                    status: active
                    currency: USD
                    purchasePrice: "48000.00"
                    purchasedAmount: "60000.00"
                    remainingPurchasedAmount: "58574.95"
                    remittanceRate: "0.12"
                    projectedCompletionDate: 2027-07-04
                    version: 9
                nextCursor: null
                hasMore: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances/{advanceId}:
    get:
      tags:
        - Merchant advances
      operationId: getMerchantAdvance
      summary: Retrieve a merchant advance
      description: Returns agreement terms, balance, sales/remittance summary, projection, and breach state.
      x-permission: READ_MERCHANT_ADVANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - externalId
                  - merchantId
                  - productId
                  - status
                  - currency
                  - purchasePrice
                  - purchasedAmount
                  - remainingPurchasedAmount
                  - remittanceRate
                  - projectedCompletionDate
                  - version
                properties:
                  advanceId:
                    type: string
                  externalId:
                    type: string
                    description: Caller-controlled identifier unique within the tenant and resource type.
                  merchantId:
                    type: string
                  productId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  purchasePrice:
                    type: string
                  purchasedAmount:
                    type: string
                  remainingPurchasedAmount:
                    type: string
                  remittanceRate:
                    type: string
                  projectedCompletionDate:
                    type: string
                    format: date
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                externalId: northstar-advance-2026
                merchantId: party_NORTHSTAR_4
                productId: prod_MERCHANT_ADVANCE_1
                status: active
                currency: USD
                purchasePrice: "48000.00"
                purchasedAmount: "60000.00"
                remainingPurchasedAmount: "58574.95"
                remittanceRate: "0.12"
                projectedCompletionDate: 2027-07-04
                version: 9
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
    put:
      tags:
        - Merchant advances
      operationId: updateSubmittedMerchantAdvance
      summary: Update a submitted merchant advance
      description: Updates proposed terms before approval and regenerates projections.
      x-permission: UPDATE_MERCHANT_ADVANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - externalId
                  - merchantId
                  - productId
                  - status
                  - currency
                  - purchasePrice
                  - purchasedAmount
                  - remainingPurchasedAmount
                  - remittanceRate
                  - projectedCompletionDate
                  - version
                properties:
                  advanceId:
                    type: string
                  externalId:
                    type: string
                    description: Caller-controlled identifier unique within the tenant and resource type.
                  merchantId:
                    type: string
                  productId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  purchasePrice:
                    type: string
                  purchasedAmount:
                    type: string
                  remainingPurchasedAmount:
                    type: string
                  remittanceRate:
                    type: string
                  projectedCompletionDate:
                    type: string
                    format: date
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                externalId: northstar-advance-2026
                merchantId: party_NORTHSTAR_4
                productId: prod_MERCHANT_ADVANCE_1
                status: submitted
                currency: USD
                purchasePrice: "48000.00"
                purchasedAmount: "60000.00"
                remainingPurchasedAmount: "58574.95"
                remittanceRate: "0.12"
                projectedCompletionDate: 2027-07-04
                version: 2
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - terms
                - expectedVersion
              properties:
                terms:
                  type: object
                  required:
                    - purchasePrice
                    - purchasedAmount
                    - remittanceRate
                  properties:
                    purchasePrice:
                      type: string
                    purchasedAmount:
                      type: string
                    remittanceRate:
                      type: string
                expectedVersion:
                  type: integer
              example:
                terms:
                  purchasePrice: "48000.00"
                  purchasedAmount: "60000.00"
                  remittanceRate: "0.12"
                expectedVersion: 1
            example:
              terms:
                purchasePrice: "48000.00"
                purchasedAmount: "60000.00"
                remittanceRate: "0.12"
              expectedVersion: 1
  /v1/merchant-advances/{advanceId}/approve:
    post:
      tags:
        - Merchant advances
      operationId: approveMerchantAdvance
      summary: Approve a merchant advance
      description: Approve a merchant advance with a versioned commercial decision and reasons.
      x-permission: DECIDE_MERCHANT_ADVANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - previousStatus
                  - status
                  - version
                properties:
                  advanceId:
                    type: string
                  previousStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                previousStatus: submitted
                status: approved
                version: 3
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - approvedOn
                - approvedPurchasePrice
                - decisionId
                - expectedVersion
              properties:
                approvedOn:
                  type: string
                approvedPurchasePrice:
                  type: string
                decisionId:
                  type: string
                expectedVersion:
                  type: integer
              example:
                approvedOn: 2026-09-03
                approvedPurchasePrice: "48000.00"
                decisionId: decision_NORTHSTAR_4
                expectedVersion: 2
            example:
              approvedOn: 2026-09-03
              approvedPurchasePrice: "48000.00"
              decisionId: decision_NORTHSTAR_4
              expectedVersion: 2
  /v1/merchant-advances/{advanceId}/reject:
    post:
      tags:
        - Merchant advances
      operationId: rejectMerchantAdvance
      summary: Reject a merchant advance
      description: Reject a merchant advance with a versioned commercial decision and reasons.
      x-permission: DECIDE_MERCHANT_ADVANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - previousStatus
                  - status
                  - version
                properties:
                  advanceId:
                    type: string
                  previousStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                previousStatus: submitted
                status: rejected
                version: 3
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCodes
                - expectedVersion
              properties:
                reasonCodes:
                  type: array
                  items:
                    type: string
                expectedVersion:
                  type: integer
              example:
                reasonCodes:
                  - merchant_request
                expectedVersion: 2
            example:
              reasonCodes:
                - merchant_request
              expectedVersion: 2
  /v1/merchant-advances/{advanceId}/withdraw:
    post:
      tags:
        - Merchant advances
      operationId: withdrawMerchantAdvance
      summary: Withdraw a merchant advance
      description: Withdraw a merchant advance with a versioned commercial decision and reasons.
      x-permission: DECIDE_MERCHANT_ADVANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - previousStatus
                  - status
                  - version
                properties:
                  advanceId:
                    type: string
                  previousStatus:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  version:
                    type: integer
                    description: Monotonically increasing resource version.
              example:
                advanceId: ma_northstar_6N8Q
                previousStatus: submitted
                status: withdrawn
                version: 3
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - reasonCodes
                - expectedVersion
              properties:
                reasonCodes:
                  type: array
                  items:
                    type: string
                expectedVersion:
                  type: integer
              example:
                reasonCodes:
                  - merchant_request
                expectedVersion: 2
            example:
              reasonCodes:
                - merchant_request
              expectedVersion: 2
  /v1/merchant-advances/{advanceId}/funding-intents:
    post:
      tags:
        - Merchant advances
      operationId: fundMerchantAdvance
      summary: Fund a merchant advance
      description: Creates the purchase-price payout to the verified merchant and activates only after posting.
      x-permission: CREATE_FUNDING
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - fundingIntentId
                  - advanceId
                  - status
                  - amount
                properties:
                  fundingIntentId:
                    type: string
                  advanceId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  amount:
                    type: string
                    description: Decimal monetary amount encoded as a string.
              example:
                fundingIntentId: fund_NORTHSTAR_1
                advanceId: ma_northstar_6N8Q
                status: approval_required
                amount: "48000.00"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - amount
                - currency
                - paymentInstrumentId
                - rail
              properties:
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                paymentInstrumentId:
                  type: string
                rail:
                  type: string
              example:
                amount: "48000.00"
                currency: USD
                paymentInstrumentId: pi_NORTHSTAR_BANK_1
                rail: ach_credit
            example:
              amount: "48000.00"
              currency: USD
              paymentInstrumentId: pi_NORTHSTAR_BANK_1
              rail: ach_credit
  /v1/merchant-advances/{advanceId}/sales-reports:
    post:
      tags:
        - Merchant advances
      operationId: createMerchantSalesReport
      summary: Record a merchant sales report
      description: Records verified settled sales, calculates remittance, and does not reduce balance until money posts.
      x-permission: CREATE_MERCHANT_REPORT
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - salesReportId
                  - advanceId
                  - periodStart
                  - periodEnd
                  - settledSales
                  - calculatedRemittance
                  - status
                  - sourceReference
                properties:
                  salesReportId:
                    type: string
                  advanceId:
                    type: string
                  periodStart:
                    type: string
                  periodEnd:
                    type: string
                  settledSales:
                    type: string
                  calculatedRemittance:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  sourceReference:
                    type: string
              example:
                salesReportId: msr_91DC
                advanceId: ma_northstar_6N8Q
                periodStart: 2026-09-08
                periodEnd: 2026-09-09
                settledSales: "11875.40"
                calculatedRemittance: "1425.05"
                status: accepted
                sourceReference: settlement_884210
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - periodStart
                - periodEnd
                - currency
                - settledSales
                - source
                - sourceReference
              properties:
                periodStart:
                  type: string
                periodEnd:
                  type: string
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                settledSales:
                  type: string
                source:
                  type: string
                  description: System or actor that originated the record.
                sourceReference:
                  type: string
              example:
                periodStart: 2026-09-08
                periodEnd: 2026-09-09
                currency: USD
                settledSales: "11875.40"
                source: processor_report
                sourceReference: settlement_884210
            example:
              periodStart: 2026-09-08
              periodEnd: 2026-09-09
              currency: USD
              settledSales: "11875.40"
              source: processor_report
              sourceReference: settlement_884210
    get:
      tags:
        - Merchant advances
      operationId: listMerchantSalesReports
      summary: List merchant sales reports
      description: Lists reports, source freshness, adjustments, remittance calculations, and reconciliation.
      x-permission: READ_MERCHANT_ADVANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - salesReportId
                        - advanceId
                        - periodStart
                        - periodEnd
                        - settledSales
                        - calculatedRemittance
                        - status
                        - sourceReference
                      properties:
                        salesReportId:
                          type: string
                        advanceId:
                          type: string
                        periodStart:
                          type: string
                        periodEnd:
                          type: string
                        settledSales:
                          type: string
                        calculatedRemittance:
                          type: string
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        sourceReference:
                          type: string
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - salesReportId: msr_91DC
                    advanceId: ma_northstar_6N8Q
                    periodStart: 2026-09-08
                    periodEnd: 2026-09-09
                    settledSales: "11875.40"
                    calculatedRemittance: "1425.05"
                    status: accepted
                    sourceReference: settlement_884210
                nextCursor: null
                hasMore: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances/{advanceId}/remittances:
    post:
      tags:
        - Merchant advances
      operationId: createMerchantRemittance
      summary: Create a merchant remittance
      description: Initiates or records a sales-based remittance and posts balance only after settlement.
      x-permission: CREATE_MERCHANT_REMITTANCE
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "201":
          description: Created.
          content:
            application/json:
              schema:
                type: object
                required:
                  - remittanceId
                  - advanceId
                  - salesReportIds
                  - amount
                  - currency
                  - status
                  - effectiveDate
                  - remainingPurchasedAmount
                properties:
                  remittanceId:
                    type: string
                  advanceId:
                    type: string
                  salesReportIds:
                    type: array
                    items:
                      type: string
                  amount:
                    type: string
                    description: Decimal monetary amount encoded as a string.
                  currency:
                    type: string
                    pattern: ^[A-Z]{3}$
                    description: ISO 4217 currency code.
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  effectiveDate:
                    type: string
                    format: date
                    description: Business-effective date in ISO 8601 format.
                  remainingPurchasedAmount:
                    type: string
              example:
                remittanceId: rem_NORTHSTAR_81
                advanceId: ma_northstar_6N8Q
                salesReportIds:
                  - msr_91DC
                amount: "1425.05"
                currency: USD
                status: submitted
                effectiveDate: 2026-09-10
                remainingPurchasedAmount: "60000.00"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - salesReportIds
                - amount
                - currency
                - paymentInstrumentId
                - rail
                - effectiveDate
              properties:
                salesReportIds:
                  type: array
                  items:
                    type: string
                amount:
                  type: string
                  description: Decimal monetary amount encoded as a string.
                currency:
                  type: string
                  pattern: ^[A-Z]{3}$
                  description: ISO 4217 currency code.
                paymentInstrumentId:
                  type: string
                rail:
                  type: string
                effectiveDate:
                  type: string
                  format: date
                  description: Business-effective date in ISO 8601 format.
              example:
                salesReportIds:
                  - msr_91DC
                amount: "1425.05"
                currency: USD
                paymentInstrumentId: pi_NORTHSTAR_BANK_1
                rail: ach_debit
                effectiveDate: 2026-09-10
            example:
              salesReportIds:
                - msr_91DC
              amount: "1425.05"
              currency: USD
              paymentInstrumentId: pi_NORTHSTAR_BANK_1
              rail: ach_debit
              effectiveDate: 2026-09-10
    get:
      tags:
        - Merchant advances
      operationId: listMerchantRemittances
      summary: List merchant remittances
      description: Lists remittance intent, settlement, allocation, return, and reconciliation.
      x-permission: READ_MERCHANT_ADVANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: pageSize
          in: query
          required: false
          description: Maximum records to return, subject to the endpoint cap.
          schema:
            type: integer
            minimum: 1
            maximum: 200
            default: 50
        - name: cursor
          in: query
          required: false
          description: Opaque cursor from the previous page.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - data
                  - nextCursor
                  - hasMore
                properties:
                  data:
                    type: array
                    items:
                      type: object
                      required:
                        - remittanceId
                        - advanceId
                        - salesReportIds
                        - amount
                        - currency
                        - status
                        - effectiveDate
                        - remainingPurchasedAmount
                      properties:
                        remittanceId:
                          type: string
                        advanceId:
                          type: string
                        salesReportIds:
                          type: array
                          items:
                            type: string
                        amount:
                          type: string
                          description: Decimal monetary amount encoded as a string.
                        currency:
                          type: string
                          pattern: ^[A-Z]{3}$
                          description: ISO 4217 currency code.
                        status:
                          type: string
                          description: Current normalized lifecycle state.
                        effectiveDate:
                          type: string
                          format: date
                          description: Business-effective date in ISO 8601 format.
                        remainingPurchasedAmount:
                          type: string
                  nextCursor:
                    type: string
                  hasMore:
                    type: boolean
              example:
                data:
                  - remittanceId: rem_NORTHSTAR_81
                    advanceId: ma_northstar_6N8Q
                    salesReportIds:
                      - msr_91DC
                    amount: "1425.05"
                    currency: USD
                    status: posted
                    effectiveDate: 2026-09-10
                    remainingPurchasedAmount: "58574.95"
                nextCursor: null
                hasMore: false
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances/{advanceId}/projection:
    get:
      tags:
        - Merchant advances
      operationId: getMerchantAdvanceProjection
      summary: Retrieve remittance projection
      description: Returns a versioned forecast; projected dates are not contractual maturity promises.
      x-permission: READ_MERCHANT_ADVANCE
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - projectionVersion
                  - asOf
                  - projectedCompletionDate
                  - assumptions
                  - periods
                properties:
                  advanceId:
                    type: string
                  projectionVersion:
                    type: integer
                  asOf:
                    type: string
                    format: date-time
                    description: Time at which the source says the fact was true.
                  projectedCompletionDate:
                    type: string
                    format: date
                  assumptions:
                    type: object
                    required:
                      - expectedMonthlySales
                      - remittanceRate
                    properties:
                      expectedMonthlySales:
                        type: string
                      remittanceRate:
                        type: string
                  periods:
                    type: array
                    items:
                      type: object
                      required:
                        - month
                        - projectedSales
                        - projectedRemittance
                        - projectedRemaining
                      properties:
                        month:
                          type: string
                        projectedSales:
                          type: string
                        projectedRemittance:
                          type: string
                        projectedRemaining:
                          type: string
              example:
                advanceId: ma_northstar_6N8Q
                projectionVersion: 5
                asOf: 2026-09-10
                projectedCompletionDate: 2027-07-04
                assumptions:
                  expectedMonthlySales: "50000.00"
                  remittanceRate: "0.12"
                periods:
                  - month: 2026-10
                    projectedSales: "50000.00"
                    projectedRemittance: "6000.00"
                    projectedRemaining: "52574.95"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances/{advanceId}/reconciliation:
    get:
      tags:
        - Merchant advances
      operationId: getMerchantAdvanceReconciliation
      summary: Retrieve merchant reconciliation
      description: Explains sales report, remittance, settlement, and balance differences by reporting period.
      x-permission: READ_RECONCILIATION
      x-idempotent: false
      security:
        - oauth2:
            - lending:read
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - status
                  - periods
                properties:
                  advanceId:
                    type: string
                  status:
                    type: string
                    description: Current normalized lifecycle state.
                  periods:
                    type: array
                    items:
                      type: object
                      required:
                        - periodStart
                        - periodEnd
                        - reportedSales
                        - calculatedRemittance
                        - settledRemittance
                        - postedRemittance
                        - difference
                      properties:
                        periodStart:
                          type: string
                        periodEnd:
                          type: string
                        reportedSales:
                          type: string
                        calculatedRemittance:
                          type: string
                        settledRemittance:
                          type: string
                        postedRemittance:
                          type: string
                        difference:
                          type: string
              example:
                advanceId: ma_northstar_6N8Q
                status: matched
                periods:
                  - periodStart: 2026-09-08
                    periodEnd: 2026-09-09
                    reportedSales: "11875.40"
                    calculatedRemittance: "1425.05"
                    settledRemittance: "1425.05"
                    postedRemittance: "1425.05"
                    difference: "0.00"
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
  /v1/merchant-advances/{advanceId}/breach-evaluations:
    post:
      tags:
        - Merchant advances
      operationId: evaluateMerchantBreach
      summary: Evaluate merchant breach status
      description: Evaluates versioned near-breach and breach rules from fresh sales, reporting, remittance, and agreement facts.
      x-permission: EVALUATE_MERCHANT_BREACH
      x-idempotent: true
      security:
        - oauth2:
            - lending:write
      parameters:
        - name: LendEasy-Tenant
          in: header
          required: true
          description: "Tenant selector: lowercase letters, digits, and hyphens, 1-64 characters. Exactly one instance; the only
            tenant selector honored."
          schema:
            type: string
            pattern: ^[a-z0-9][a-z0-9-]{0,63}$
        - name: advanceId
          in: path
          required: true
          description: Stable opaque advance identifier.
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: false
          description: "Optional stable key (1-50 chars) for this one logical mutation. Replays of a completed request return the
            original result with x-served-from-cache: true; an in-flight duplicate returns 409 with Retry-After. Omitted
            keys are server-generated per attempt."
          schema:
            type: string
            minLength: 1
            maxLength: 50
      responses:
        "200":
          description: Successful response.
          content:
            application/json:
              schema:
                type: object
                required:
                  - advanceId
                  - outcome
                  - nearBreachIndicators
                  - rulesVersion
                  - evaluatedAt
                properties:
                  advanceId:
                    type: string
                  outcome:
                    type: string
                  nearBreachIndicators:
                    type: array
                    items:
                      type: object
                  rulesVersion:
                    type: string
                  evaluatedAt:
                    type: string
                    format: date-time
              example:
                advanceId: ma_northstar_6N8Q
                outcome: no_breach
                nearBreachIndicators: []
                rulesVersion: merchant-breach-v3
                evaluatedAt: 2026-10-01T08:00:01-07:00
        "400":
          description: "Malformed request: unknown field or query parameter, invalid value, or a missing or invalid tenant header."
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "400"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: validation.msg.validation.errors.exist
                errors: []
        "401":
          description: Missing or invalid credentials.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "401"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authenticated
                errors: []
        "403":
          description: Caller lacks the required permission or case authority.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "403"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.not.authorized
                errors: []
        "404":
          description: Resource not found or not visible to the caller.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "404"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: error.msg.resource.not.found
                errors: []
        "409":
          description: State conflict, an idempotent request still in flight (includes Retry-After), or a single-entry conflict.
          content:
            application/json:
              schema:
                type: object
                required:
                  - developerMessage
                  - httpStatusCode
                  - defaultUserMessage
                  - userMessageGlobalisationCode
                  - errors
                properties:
                  developerMessage:
                    type: string
                  httpStatusCode:
                    type: string
                  defaultUserMessage:
                    type: string
                  userMessageGlobalisationCode:
                    type: string
                  errors:
                    type: array
                    items:
                      type: object
              example:
                developerMessage: Request was understood but rejected; inspect errors for field-level causes.
                httpStatusCode: "409"
                defaultUserMessage: The request could not be applied.
                userMessageGlobalisationCode: idempotency.request.in.flight
                errors: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - asOf
              properties:
                asOf:
                  type: string
                  format: date-time
                  description: Time at which the source says the fact was true.
              example:
                asOf: 2026-10-01T08:00:00-07:00
            example:
              asOf: 2026-10-01T08:00:00-07:00
components:
  securitySchemes:
    oauth2:
      type: oauth2
      description: OAuth 2.0 client credentials. Tenant and granted permissions are derived from the issued token.
      flows:
        clientCredentials:
          tokenUrl: https://auth.lendeasy.ai/oauth2/token
          scopes:
            servicing:read: Read servicing records.
            servicing:write: Create servicing work and interactions.
            lending:read: Read customers, loans, and money movement.
            lending:write: Create and mutate lending records.
            actions:approve: Approve governed actions.
